Objective-C的一些语言点梳理

来源:互联网 发布:知乎指数 编辑:程序博客网 时间:2024/05/21 10:22

首先,Objective-C是C语言的超集,在C的基础上增加了面向对象编程的语言特性。

类定义

类的声明和定义由.h和.m文件组成。头文件中声明类的一些公共特性(例如属性和方法),这些特性开放给外部使用(通过类/类的实例化/继承使用),这就相当于是类定义的接口。头文件既是一个文档化的接口说明也是辅助编译器的手段。另外一些只在类的内部使用的属性和方法则只在.m文件中声明和定义,这样可以对外部隐藏一些内部的实现细节。在头文件中还可以定义类的实例变量(Instance variable),出于进行良好封装的设计目的,实例变量一般通过属性(property)来替代(属性只能通过访问器读取和存取器进行设置)。

演示代码1:

@interface Fraction: NSObject {     int numerator;     int denominator; }- (void)print;- (int)numerator;- (void)setNumerator: (int) n; - (int)denominator;- (void)setDenominator: (int) d;@end

numerator和denominator是实例变量。以 - 打头的是实例方法,以 + 打头的是类方法。numerator和setNumerator:分别是访问和设置实例变量numerator值的实例方法。denominator和setDenominator:分别是访问和设置实例变量denominator值的实例方法。: NSObject还表明该类继承自NSObject。

演示代码2:

@interface Fraction: NSObject @property (nonatomic, strong) int numerator;@property (nonatomic, strong) int denominator;- (void)print;@end
演示代码2中用属性取代了实例变量,属性的访问器和存取器方法可以通过在.m文件中使用@synthensize语句自动产生,例如@synthesize numerator = _synthesize;

实现文件:

@implementation Fraction@synthesize numerator = _numerator;@synthesize denominator = _denominator;- (void)print{    //implement method print here}@end

定义私有属性和方法:

@interface Fraction()@property (nonatomic, strong) int result;@end
私有方法直接在.m文件中定义即可,注意定义顺序避免前向引用(Forward reference)。

方法调用

Objective-C中方法调用的语法是[obj method]; 如果是访问类属性,则可以通过dot操作符访问存取器和访问器。

演示代码:

Fraction *f = [[Fraction alloc] init];f.numerator = 1;f.denominator = 3;[f print];

有多个参数的方法定义

- (void)setTo: (int)n over: (int)d;

该方法的两个参数都有名字:setTo和over,该方法名称为setTo:over:方法。

方法调用:[aFraction setTo: 1 over: 3];
- (void)set: (int)n: (int)d;
第二个参数没有名字,该方法的名称为set::方法,两个冒号表明该方法需要两个参数,计时他们没有被命名。
方法调用:[aFraction set: 1 : 3];
第一种(也是推荐的命名方法)的优点是可读性强。

实例本身通过self关键字引用,父对象通过super关键字引用

多态、动态类型、动态绑定

多态(Polymorphism)顾名思义就是可以呈现多种形态,怎么呈现多种形态呢?对同名方法的调用会根据对象的不同调用不同对象的同名方法。它的好处有很多,例如便于抽象,代码复用等。其实面向对象的编程语言貌似都支持多态(例如C++, Java, Python)。动态类型是用id类表示指向对象的指针,但是该对象具体是什么类型则要等到运行时才能确定。动态类型可以很好的支持多态,但是它也使得编译器无法进行编译时检查,因此不要滥用动态类型,尽可能的让问题在编译时暴露出来。动态绑定是根据对象的具体类型在运行时将方法调用绑定到具体的对象方法上。动态类型、动态绑定都是支持多态的必要特性。


协议(Protocol)

Objective-C不支持多重继承(C++支持多重继承),它通过协议支持一些多重继承提供的语言特性。协议就是事先约定好的一些接口,通过这些约定好的接口双方才能进行通信,就像通信协议那样。协议通常在一个类中定义,其它需要和该类通信的类则需要实现遵循这个协议的约定,实现协议中定义的方法。举一个通俗的例子:

Girl定义了一个协议MarryMe,所有想要和Girl结婚的Boy都必须遵循该协议(因为没有其它途径),该协议是什么呢?协议就是Girl认为Boy要和她结婚需要具备的一些条件,也就是要实现一些接口。如果Girl定义的MarryMe协议如下:

@protocol MarryMe- (BOOL)hasHouse;- (BOOL)hasCar;- (BOOL)nice;@end
Boy必须实现所有这3个接口才可以与Girl就结婚的事情进行交流。协议中的方法也不是必须所有都实现,可以在协议中声明一些可选的接口(@optional),默认是必需的(@required)。
iOS开发中的主要使用的设计模式MVC中,模块之间的通信可以通过设置代理(delegate)的方式完成,通常也就是定义一套双方之间的通信协议。


Category

Category提供了一种对类定义的相关方法模块化到不同分组(groups)或类别(categories)中的简单方法。它也提供了一种扩展现存类的简单方法,简单到什么程度呢?你不需要有访问原有类源代码的权限,不需要创建原有类的子类。例如:

原有类:

@interface Fruit : NSObject

@property (nonatomic, strong) float costPrice;

- (float)defaultSellingPrice;

@end

现在搞促销活动,需要打折了,轻量级的能满足需求的扩展便是通过Category。

@interface Fruit(Discount)

- (float) discountSellingPrice;

@end

这里可能没有权限访问Fruit的源代码,无法直接更改Fruit类。即使能更改,可能也因为不想扩散修改Fruit类的影响而不愿意修改。而子类化Fruit类则显得有点“杀鸡用牛刀”了,这里仅仅是增加一个方法而已。上面的接口定义告诉编译器增加了一个名为Discount的扩展到Fruit类中。这个扩展(Category)可以访问原有类(Fruit)的实例变量,但是不能增加实例变量。如果需要增加实例变量则说明这个改动规模有点大,应该考虑子类化了。在Category中也可以覆写原有类的方法,但是这通常不是一个好的设计,因为覆写之后就再也无法访问原方法了。可以定义一个类下的多个Category,也就是为一个类增加多个扩展。如果同名方法在多个Category中存在,选择哪个执行是不确定的。可以不用全部实现category中的方法,可以在将来逐步增量实现。在Category中增加方法会影响到原有类的子类,通常约定category的实现文件的命名方法为:

OrginalClassName+CagegoryName.h[m]。例如Fruit+Discount.h, Fruit+Discount.m。