原文:http://rypress.com/tutorials/objective-c/protocols
协议
协议是一组相关的属性和方法的集合,它能够被任何类所实现。协议比一般的类的接口更加灵活,他能在不同类之间建立一个统一的API定义,这样不同类如果实现相同的协议则能被抽象相同的协议。
Unrelated classes adopting the StreetLegal
protocol
本章介绍基本饿协议的知识。我们也将学习到协议在动态特性中的使用。
创建协议
就像一般的类的接口文件一样,协议也被定义在.h文件中。点击navigate to File > New> File…或者快捷键 Cmd+N ,OS > Cocoa Touch分类中选择 Objective-C protocol去创建协议。【xf-xrh-xf译注:不同的xcode版本会有不同操作】
Creating a protocol in Xcode
在这个章节中我们将创建一个叫做StreetLegal的协议。在对话框中输入StreetLegal作为名称把他保存在项目的根目录。
我们的协议将定义一些必须的车辆的行为方法。通过协议可以将这些方法在制定对象上生效而无需使用集成类的办法完成。一个简单的StreetLegal的例子如下:
// StreetLegal.h #import <Foundation/Foundation.h> @protocol StreetLegal <NSObject> - (void)signalStop; - (void)signalLeftTurn; - (void)signalRightTurn; @end
任何实现这个协议的对象必须实现在协议中定义的所有方法。在协议名后面的<NSObject>表示NSObject
protocol(注意不要和NSObject
class搞混)。
接口实现
如某个类想要实现接口则可以在接口文件中在类名后面使用尖括号将协议包起来。我们新建一个叫做Bicycle的类它实现了StreetLegal协议,具体写法如下:
// Bicycle.h #import <Foundation/Foundation.h> #import "StreetLegal.h" @interface Bicycle : NSObject <StreetLegal> - (void)startPedaling; - (void)removeFrontWheel; - (void)lockToStructure:(id)theStructure; @end
协议的实现就像将所有在协议中定义的方法写在类头文件中一样。即使Bicycle类是其他类的子类等操作方法都是一样的。如果要实现多个协议则使用都好相隔(例如:<StreetLegal, SomeOtherProtocol>)。
在Bicycle的实现文件中其实和一般的写法没有什么不同,只是需要将所实现的协议方法都在实现文件中实现即可:
// Bicycle.m #import "Bicycle.h" @implementation Bicycle - (void)signalStop { NSLog(@"Bending left arm downwards"); } - (void)signalLeftTurn { NSLog(@"Extending left arm outwards"); } - (void)signalRightTurn { NSLog(@"Bending left arm upwards"); } - (void)startPedaling { NSLog(@"Here we go!"); } - (void)removeFrontWheel { NSLog(@"Front wheel is off." "Should probably replace that before pedaling..."); } - (void)lockToStructure:(id)theStructure { NSLog(@"Locked to structure. Don‘t forget the combination!"); } @end
现在,当你Bicycle类的时候,你就能使用在协议定义的API(方法)了。
// main.m #import <Foundation/Foundation.h> #import "Bicycle.h" int main(int argc, const char * argv[]) { @autoreleasepool { Bicycle *bike = [[Bicycle alloc] init]; [bike startPedaling]; [bike signalLeftTurn]; [bike signalStop]; [bike lockToStructure:nil]; } return 0; }
Type Checking With Protocols
就像类一样,协议也可作为一个变量类型使用。具体如下:
// main.m #import <Foundation/Foundation.h> #import "Bicycle.h" #import "Car.h" #import "StreetLegal.h" int main(int argc, const char * argv[]) { @autoreleasepool { id <StreetLegal> mysteryVehicle = [[Car alloc] init]; [mysteryVehicle signalLeftTurn]; mysteryVehicle = [[Bicycle alloc] init]; [mysteryVehicle signalLeftTurn]; } return 0; }
无论Car和Bicycle是否继承于同一个父类,事实上只要他们都实现了同一个协议那么他们就能使用id <StreetLegal>变量来存储。这个例子就是告诉我们这一点。
使用conformsToProtocol:方法可以检查对象是否实现了某个协议:这个方法被定义基础协议NSObject中。我们使用 @protocol()来讲协议协议名称作为参数传入,
这个很像@selector(),只是@selector()将方法名称放入其中。就像这样:
if ([mysteryVehicle conformsToProtocol:@protocol(StreetLegal)]) { [mysteryVehicle signalStop]; [mysteryVehicle signalLeftTurn]; [mysteryVehicle signalRightTurn]; }
使用协议就像在说:“确认一下这个对象中实现了一些特定方法”。协议是一个非常强大的动态编程的技术,这能够是你的API更加灵活,你在使用API的时候不用担心到底去声明哪个类去解析。
实践协议
其实在你IOS和OSx应用开发过程中你已经在使用了很多的协议了。比如“application delegate”对象就是之一。 UIKit Framework进场要求你使用到该协议:
@interface YourAppDelegate : UIResponder <UIApplicationDelegate>
总结
在本章节中,我们又获得了一个很好的工具。协议是一种首相属性和方法的工具。帮助你减少冗余代码。使你动态的调用实现同一协议的不同对象。
你可以在 Cocoa frameworks中找到很多协议的例子。一个简单的使用场景就是不用去subclass一个类但是也可以改变他的行为。例如, Table View, Outline View, 和 Collection ViewUI部件都需要使用到data source 和 delegate对象去定义数据和行为。但是data source 和 delegate其实都是协议,所以你可以在任何地方定义他们并使用他们。
下一章节我们将介绍分类,是一种能够模块化组织类和提供一些巧妙用法。