协议在ios中的使用

来源:互联网 发布:羊绒大衣 知乎 编辑:程序博客网 时间:2024/06/05 16:09

协议:

在Cocoa中,协议分为“正式协议”和“非正式协议”两种,使用他们的好处有很多,具体如下:

非正式协议:

非正式协议包含了属性和方法的列表,同时可以不用显示的采用这个协议;也就是我们可以只实现需要实现的协议规则即可,这点与正式协议正好相反。

正式协议:

与非正式协议一样,正式协议也包含了属性和方法的名称列表。但与非正式协议不同的是,正式协议要求显示的采用。采用协议的方法是在@interface声明中列出协议的名称。采用协议之后,我们的类就必须遵循这个协议,也就意味着必须实现该协议的所有的方法(这点和java中的接口很相似,估计是受了java接口的启发吧),否者编译器会报错提示。

协议声明:

声明协议的语法和声明类或类别有些类似,不过使用的不是@interface而是@protocol,它后面即为协议的名称(唯一)。另外,协议与类相似的地方是支持继承机制的,即只需在声明语句协议名称后面的尖括号内指定父协议名称即可。具体如下样例:

@protocol MyProtocol <MyParentProtocol>

@end

第一行代码代表协议MyProtocol继承自父协议MyParentProtocol,所以就必须实现两个协议的所有需要协定实现的方法。通常可以采用NSObject作为根协议(与类NSObject不同,类NSObject支持所有的根协议实现),因此就意味着所有的对象都支持根协议了。将NSObject作为你编写协议的父协议是不错的习惯和做法。

下面来看下Cocoa中的两个协议的声明语法:

@protocol NSCopying

- (id) copyWithZone : (NSZone *) zone;

@end

 

@protocol NSCoding 

- (void) encodeWithCoder : (NSCoder *) encoder;

- (id) initWithCoder : (NSCoder *) decoder;

@end 

 

协议的使用:

要使用某个协议,可以在类的声明中列出该类的协议名称,并用尖括号括起来即可。具体如下所示使用:

单个协议:

@interface Car : NSObject <NSCopying>

{
// ...

}

@end

 

多个协议

@interface Car : NSObject <NSCoding,NSCopying>

{

// ...

}

@end

 

基于协议的复制:

正如在内存管理规则:“如果使用了alloc、new及copy”的时候,就会获得一个对象,同时对象的引用计数值为1,并且需要释放它。

对于复制又分为两种:“浅层复制”和“深层复制”。

浅层复制(shallow copy):

此类复制不会复制引用的对象,复制的对象只会指向现有的对象的基本属性和方法。如果复制的对象包含了NSString的NSArray数组对象,那么新复制的对象只是指向对象的指针并不是实际值地址。

 

深层复制(deep copy):

此类复制会复制所有的引用对象。如果NSArray的copy方法是深层复制,那么复制的对象就包含了指向对象的指针以及该对象的本身。

 

下面就以CarParts项目为实例来使用复制技术,我们以复制Car类开始吧!因为Car类中引用了Engine和Tire类,所以这里使用深层复制来完成这个功能。

 

复制Engine:

声明:

@interface Engine : NSObject<NSCopying>

@end

实现:

- (id) copyWithZone:(NSZone *) zone

{

Engine *enigneCopy;

enigneCopy = [[[self classallocWithZone:zone] init];

return (enigneCopy);

}

// comments

正如上面的代码所示,我们在Engine的类声明中为其添加了NSCopying协议,那么该引擎类就必须实现这个协议所要求实现的所有方法,当然这里只有一个copyWithZone()方法。因为Engine一开始为NULL,所以需要在协议实现中创建该实例对象,并为其分配内存空间块。另外,对于Engine的子类也是需要复制的,但由于该子类没有添加任何属性和方法,所以没有必要实现copyWithZone()方法,直接交由继承机制支持子类赋值即可。

复制Tire:

声明:

@interface Tire : NSObject<NSCopying>

实现:

- (id) copyWithZone:(NSZone *) zone

{

Tire *tireCopy;

tireCopy = [[[self classcopyWithZone:zone] initWithPressure:pressure treadDepth:treadDepth];

return (tireCopy);

}

赋值AllWealtherRadial

声明:

实现:

- (id) copyWithZone:(NSZone *) zone

{

AllWealtherRadial *subTireCopy;

subTireCopy = [super copyWithZone:zone];

subTireCopy.snowHandling = snowHandling;

subTireCopy.rainHandling = rainHandling;

return (subTireCopy);

}

//comments

对于汽车轮胎Tire的复制与引擎Engine的复制类似,不过不同的是Tire的子类是需要我们添加复制处理的。Tire的复制和Engine的相同,只需为其创建一个内存空间块,并将对象分配即可。而Tire其子类AllWealtherRadial 需要我们告诉编译器需要显示复制该子类中的属性和方法,所以我们需要在子类AllWealtherRadial 中实现copyWithZone()方法即可,并不需要在声明中声明协议,因为复制协议是支持继承机制的。 

 

复制Car:

声明:

@interface Car:NSObject<NSCopying>

{

NSString *appellation;

Engine *engine;

NSMutableArray *tires;

}

实现:

- (id) copyWithZone:(NSZone *) zone

{

Car *carCopy;

carCopy = [[[self classcopyWithZone:zone] init];

carCopy.name = self.name;

Engine *engineCopy;

engineCopy = [[engine copyautorelease];

carCopy.engine = engineCopy;

for(int i=0;i<4;i++)

{

Tire *tireCopy;

tireCopy = [[self tireAtIndex:i] copy];

[tireCopy autorelease];

[carCopy setTire:tireCopy atIndex:i];

}

[carCopy autorelease];

return (carCopy);

}

// comments

对于汽车类Car的复制和Engine的复制类似,即先为其分配指定的内存空间区域即可。值得关注的是在这里需要复制汽车引擎和汽车轮胎的内置对象,具体实现也很简单,即是复制Engine和Tire,然后将复制的新对象指定给Car对应的引擎和轮胎属性即可。

注意:

这里的Engine、Tire的原始对象使用过后需要释放内存,可以使用release和自动释放池(推荐使用release,不过为了方便这里使用自动释放池实现);在最后,要将复制的car从内存释放。

 

类非正式协议:

在Objective-C 2.0以后,新增加了两个协议的限定符,分别为:@optional 和 @required。

上面有说到,如果类使用了正式协议,那么就必须实现协议的所有方法。但有的时候,我们想只实现必须的功能方法,而其他功能可以有选择的实现即可,这也是个好的实现机制;有的人会想到使用非正式协议,不错,非正式协议却是可以实现这个需求,不过它的可读性比较差,而且在新版本中不推荐使用非正式协议,取而代之却是这里介绍的两个修饰符。

@optional:

该修饰符修饰的协议方法是可选实现的,并不是必须实现。

@required:

与上面相反,这个修饰符限定了协议方法必须实现,与正式协议基本需求一致。

 

例如:

@protocol ShapeHelper

@optional

- (void) drawPoint;

@required

- (void) drawLine:

- (void) drawPatch;

 

注意:

Cocoa中的非正式协议已经逐渐被替换成带有@optional方法的正式协议在广泛使用了。

 

 

好了,关于在ios开发中的协议使用就介绍到这里。

 

 

 

 

 

 

 

 

/**

*  技术交流群:179914858

*/

0 0