Objective-C面向对象浅谈

  本文简述了Objective-C语言的语法(偏面向对象),以及一些个人见解。

Objective-C(之后称OC),顾名思义,是C语言面向对象的一种扩展,它保留了C语言的全部语法,并且兼容C语言,在这基础上建立了一套完整的面向对象编程体系。

在面向对象相关的语言层面上,可以说它是比较像Java的:单继承、有接口等。但是在代码中,它跟C++是比较相似的。

  让我们来看代码吧!

#import <UIKit/UIKit.h>
#import "MyClass.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

  可以看出,对于库文件、自己创建的类的引用使用了“import”关键字。这里可以说OC虽然完全支持C语言,但是一些细节OC也做了相关的优化,这里不具体陈述,我们使用其推荐的即可。

  还可以看到“@autoreleasepool”关键字,OC使用“@”来标识其特有的一些关键字以及特殊用法,如:“@interface”、 “@property”、 “@protocol” 等,可以说“@”在OC中无处不在。

  接下来说一下OC的面向对象特性。

  作为一个面向对象语言,其面向对象特性我们不得不提,我们从继承、封装以及多态来谈其面向对象特性。

  首先,需要介绍其基本的面向对象语言特性,下面来看一些基本代码:

//head file:demo.h
#import <Foundation/Foundation.h>

@interface TestClass : NSObject <NSObject>//继承NSObject类(第一个),遵守NSObject协议(第二个)

@property (nonatomic) NSInteger value;

- (void)replaceTheValueWithValue:(NSInteger)value;

@end
//source file:demo.m
#import <Foundation/Foundation.h>

@implementation TestClass

- (void)replaceTheValueWithValue:(NSInteger)value {
    self.value = value;
}

@end
//source file:main.m
#import <Foundation/Foundation.h>
#import "demo.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        TestClass *obj = [[TestClass alloc] init];
        obj.value = 1;

        NSLog(@"%ld", (long)obj.value);

        [obj replaceTheValueWithValue:1];

        NSLog(@"%ld", (long)obj.value);
    }
}

  以上代码展示了一个非常简单的类“TestClass”的定义及其简单的使用。

  “Demo.h”文件给出了类的声明,并作为一个“类的说明书”供使用者参考,而“Demo.m”文件则是给出类的定义(需要实现的部分),即给出类的必要部分的实现细节。笔者前面提到的OC与C++类似的部分就在于次。

扫描二维码关注公众号,回复: 9844202 查看本文章

  “main.m”文件则是类似于C语言一个拥有主函数的文件,它确实拥有“main”函数,作为程序的入口。其中有对象的创建、对象属性的使用、对象方法的调用,读者可以进行一下参考。

  代码中如果有不明白的地方可以自行研究。

  下面将简介其面向对象特性:

1.继承

  OC完全支持面向对象的继承特性,并且与Java语言类似,引入了类似于“接口”的“协议”。当然,本文不探讨其真正的共同点与不同点,只是拿来做参考。

  下面通过代码来学习:

//为了简化代码,将把所有内容写入一个源文件
//source code:main.m
#import <Foundation/Foundation.h>

@protocol TestProtocol <NSObject>

@optional

- (BOOL)valueFlag;

@required

- (void) replaceTheValueWithValue:(NSInteger)value;

@end

@interface TestClass : NSObject <TestProtocol>

@property (nonatomic) NSInteger value;

@end

@implementation TestClass

- (instancetype)init {
    self = [self initWithValue:0];
    return self;
}

- (instancetype)initWithValue:(NSInteger)value {
    self = [super init];

    if (self != nil) {
        self.value = value;
    }

    return self;
}

- (void)replaceTheValueWithValue:(NSInteger)value {
    self.value = value;
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        TestClass *obj = [[TestClass alloc] initWithValue:3];

        obj.value = 1;

        NSLog(@"%ld", (long)obj.value);

        [obj replaceTheValueWithValue:1];

        NSLog(@"%ld", (long)obj.value);
    }
    return 0;
}

  这里引入了一个叫“TestProtocol”的协议,而新的“TestClass”需要遵守这个协议。其中拥有一些可选(optional)和必须(required)实现的方法。

  有关继承,这里使“TestClass”继承了“NSObject”类(事实证明OC中所有的类的最终基类一定是NSObject),它提供给我们的类很多已经实现的东西(比如实例化时的内存分配方法“alloc”),OC是单继承,我们可以用协议来丰富类的方法约束,以及完成一些特殊设计模式的需求。

2.封装

  说到封装,我们就不得不提面向对象语言的访问控制,这一部分看似是比较容易的(在C++中,只需要搞清楚“public”、“protected”和“private”的区别并应用到实际设计中),但是在OC(以及新的Swift)中并不是如此,下面还是通过一段代码来说明。

#import <Foundation/Foundation.h>

@interface TestClass : NSObject {
@private
    NSInteger _value2;
@protected
    NSInteger _value3;
@public
    NSInteger _value4;
@package
    NSInteger _value5;
}

@property (nonatomic) NSInteger value;

@end

@implementation TestClass

- (void)replaceTheValueWithValue:(NSInteger)value {
    self.value = value;
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        TestClass *obj = [[TestClass alloc] init];
        obj.value = 1;
//        obj->_value2 = 1; //error
//        obj->_value3 = 1; //error
        obj->_value4 = 1;
        obj->_value5 = 1;

        [obj replaceTheValueWithValue:1];
    }
    return 0;
}

  OC也拥有类似C++的“public”、“private”、“protected”关键字,只是表现形式不一样。而且OC增加了“@package”关键字,用以表示在该程序包(类似一个依赖库一样)内显公有,对外显私有的状态。

  OC的“属性”默认访问控制模式为“@protected”,而“方法”的默认访问控制模式为“@public”,但是为什么上面的属性“value”却可以使用“.”运算符“访问”呢?因为“@property”关键字会为该属性自动生成存取方法,而方法的默认访问控制模式为“@public”,因此可以通过特殊的运算符“.”来访问。(同理大家可以试试访问方法的语法“[obj value]”和“[obj setValue:val]”是否可以用!)

  综上所述,OC实现封装还是非常容易的。

3.多态

BaseClass *obj;
obj = [[SubClass1 alloc] init];
obj = [[SubClass2 alloc] init];

  多态的实现其实对于OC并不难。首先我们可以创建一个普通的类(区别于虚类),然后用多个子类继承它,再写出类似上面部分的代码来实现多态。但是这样子如果“BaseClass”中需要有纯虚函数,虽然可以不写具体实现来忽略它,但是这样不是最佳的做法,因此我们可以用OC的“协议”来实现对纯虚函数的要求,以及多态的实现,下面通过代码来演示。

#import <Foundation/Foundation.h>

@protocol BaseProtocol <NSObject>

@required

- (void)call;

@end

@interface BaseClass : NSObject

@property (nonatomic, copy) NSString *name;

@end

@interface Dog : BaseClass <BaseProtocol>
//It's own interface like kill
@end

@interface Cat : BaseClass <BaseProtocol>
//It's own interface like jump
@end

@implementation BaseClass

- (instancetype)initWithName:(NSString *)name {
    self = [super init];
    if (self) {
        self.name = name;
    }
    return self;
}

@end

@implementation Dog

- (void)call {
    NSLog(@"%@: Wang!", self.name);
}

@end

@implementation Cat

- (void)call {
    NSLog(@"%@: Miao!", self.name);
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        BaseClass <BaseProtocol> *animal;
        animal = [[Dog alloc] initWithName:@"tom"];
        [animal call];
        animal = [[Cat alloc] initWithName:@"jerry"];
        [animal call];
    }
    return 0;
}

  可以看到,主函数中给出了运用多态的对象animal(在第57和59行调用“叫”的方法时我们不需要知道是什么在叫,只需要知道它会叫即可)而它可以实例化为其子类的对象。

  如有不对敬请指出,感谢阅读!

发布了15 篇原创文章 · 获赞 2 · 访问量 1356

猜你喜欢

转载自blog.csdn.net/yeehok/article/details/52372781