1、正式协议
与非正式协议一样,正式协议是一个命名的方法列表。但与非正式协议不同的是,正式协议要求显式地采用协议。采用协议的办法是在类的@interface声明中列出协议的名称。此时,类遵守该协议。采用协议意味着你承诺实现该协议的所有方法,否则编译器会通过警告来提醒。
实现协议的每一个方法似乎需要完成大量的工作。但是通常情况下,一个协议只有少数几个需要实现的方法,必须实现所有这些方法才能获得一系列的有用功能。
1.1、声明协议
例子:Cocoa声明的一个协议NSCopying。如果采用了NSCopying协议,你的对象将知道如何复制自己:
@protocol NSCopying
- (id) copyWithZone: (NSZone *) zone;
@end
使用@protocol告诉编译器这是一个正式协议。@protocol之后是协议名称,协议名称必须唯一。
然后是一个方法声明列表,协议的每个采用者都必须实现这些方法。协议声明以@end结束,使用协议不引入新的实例变量。
当某个类采用某个正式协议时,意味着该类承诺实现这个正式协议的所有方法。
1.2、采用协议
要采用某个协议,可以在类的声明中列出该协议的名称,并用尖括号将协议名称括起来。
@interface Car: NSObject <NSCopying>
...
@end
实现两个协议则可在尖括号中用逗号分隔。
@interface Car: NSObject: <NSCopying, NSCoding>
...
@end
可以按任何顺序列出这些协议。
1.3、实现协议
2、复制
“如果使用alloc、copy或new方法获得一个对象,则该对象的保留计数器值为1,需要负责释放它”。
copy方法可以复制对象。copy消息通知对象创建一个全新的对象,并使新对象与接收copy消息的原对象一样。
复制的种类:大多数对象都引用(即指向)其它对象,浅层复制不复制引用对象,新复制的对象只指向现有的引用对象,NSArray类的copy方法是浅层复制。当复制一个NSArray类的对象时,复制的对象只复制指向引用对象的指针。
深层复制复制所有的引用对象。
为了能对类进行复制,类需要采用NSCopying协议。
实现copyWithZone: 方法。参数是一个NSZone类的对象,指向一块可供分配的内存区域。当向一个对象发送copy消息时,该copy消息在到达你的代码之前被转换为copyWithZone: 方法。
copyWithZone: 中声明一个该对象的复制对象,然后调用[self class] 来获得本对象所属类,再调用allocWithZone: 获得一块内存空间,再调用init初始化空间。
[[[self class] allocWithZone:zone] init]
+ (id) allocWithZone: (NSZone *) zone;
copy方法应该返回一个保留计数器值为1的对象,且该对象不会自动释放。
可以使用C风格的指针运算直接访问实例变量;
tireCopy->pressure=pressure;
A类采用了NSCopying协议,B类继承A类时,则不需要再@interface中声明NSCopying协议,但是B类仍然需要实现该协议的方法。
2.4、协议和数据类型
可以在使用的数据类型中为实例变量和方法参数指定协议名称。这样,你可以给OC的编译器提供更多一点的信息。
id类型表示一个可以指向任何类型的对象的指针,它是一个泛型对象类型。可以将任何对象赋值给一个id类型的变量,也可以将一个id类型的变量赋值给任何类型的对象指针。
如果一个用尖括号括起来的协议名称跟随在id之后,则编译器将知道你期望任意类型的对象,只要其遵守该协议。
例如,NSControl类中有一个名为setObjectValue: 的方法,该方法要求对象遵守NSCopying协议:
- (void) setObjectValue: (id<NSCopying>) obj;
编译器在编译该方法时,将检查参数类型。该参数对象所属的类需采用尖括号中的协议。
3、OC2.0的新特性
OC2.0增加了两个新的协议修饰符:@optional和@required。
@required后跟随的是必须实现的方法;@optional后跟随的是可选实现的方法。
默认是@required。
通常用在协议中。
Cocoa中的非正式协议逐渐被带有@optional的正式协议取代。