iOS——协议与分类

在OC语言中有一项特性叫做协议(protocol),由于OC不支持多重继承,因而我们把某个类应该实现的一系列方法定义在协议里。协议可以很好的描述接口。

** 分类(Category)**也是OC的一种重要特性,利用分类可以直接为当前类添加方法,无需通过继承子类,契合OC语言运行期系统是高度动态的。

23:通过委托与数据源协议进行对象间通信

对象之间经常需要相互通信,而通信方式有很多种。Objective-C开发者广泛使用一种名叫"委托模式"(Delegate pattern)的编程设计模式来实现对象间的通信,该模式的主旨是:定义一套接口,某对象若想接受另一个对象的委托,则需遵从此接口,以便成为其"委托对象"(delegate)。而这"另一个对象"则可以给其委托对象回传一些信息,也可以在发生相关事件时通知委托对象。

此模式可将数据与业务逻辑解耦。比方说,用户界面里有个显示一系列数据所用的视图,那么,此视图只应包含显示数据所需的逻辑代码,而不应决定要显示何种数据以及数据之间如何交互等问题。视图对象的属性中,需要包含负责数据与事件处理的对象。这两种对象分别称为"数据源"(data source)与"委托"(delegate)。

下面举个例子:假设要便携一个从网上获取数据的类,如果网络请求时间过长,导致阻塞应用程序,这是很糟糕的,所以我们会采用委托模式.

委托模式

首先使用的这个类含有一个**“委托对象”**,在请求完数据之后,它会回调这个对象。下面是回调委托对象的过程:
在这里插入图片描述
EOCNetworkFetcher对象就是我们完成网络请求的类。
EOCDataModel对象就是 EOCNetworkFetcher的委托对象。EOCDataModel请求 EOCNetworkFetcher以异步方式执行一项任务"(perform a task asynchronously),而 EOCNetworkFetcher在执行完这项任务之后,就会通知其委托对象,也就是 EOCDataModel。
这里所谓的异步方式:即GCD中一种添加任务的方法:添加后,不必等待任务结束,函数会立即返回。推荐优先使用这种方式,因为它不会阻塞其他任务的执行。
下面看看代码:

@protocol EOCNetworkFetcherDelegate

- (void)networkFetcher:(EOCNetworkFetcher*) fetcher
didReceiveData:(NSData*)data;- (void)networkFetcher:(EOCNetworkFetcher*)fetcher didFailWithError:(NSError*)error;


@end

协议名通常是相关类名后加上Delegate。有了协议之后类就可以用一个属性来存放委托对象了。

@property (nonatomic, weak) id <EOCNetworkFetcherDelegate> delegate;

一定要注意∶这个属性需定义成weak,而非strong,因为两者之间必须为"非拥有关系"(nonowning relationship)。通常情况下,扮演 delegate 的那个对象也要持有本对象。例如在本例中,想使用EOCNetworkFetcher 的那个对象就会持有本对象,直到用完本对象之后,才会释放。假如声明属性的时候用strong将本对象与委托对象之间定为"拥有关系",那么就会引入"保留环"(retain cycle)。因此,本类中存放委托对象的这个属性要么定义成 weak,要么定义成 unsafe unretained,如果需要在相关对象销毁时自动清空,则定义为前者,若不需要自动清空,则定义为后者。
下图解释了他们的所有权关系。
在这里插入图片描述
实现委托对象的办法是声明某个类遵从委托协议,然后把协议中想实现的那些方法在类里实现出来。某类若要遵从委托协议,可以在其接口中声明,也可以在"class-continuation 分类",如果要向外界公布此类实现了某协议,那么就在接口中声明,而如果这个协议是个委托协议的话,那么通常只会在类的内部使用。所以说,这种情况一般都是在"class-continuation分类"里声明的∶

@implementation EOCDataModel () <EOCNetworkFetcherDelegate>
@end@implementation EOCDataModel


- (void)networkFetcher:(EOCNetworkFetcher*)fetcher
didReceiveData:(NSData*)data {
   /* Handle data */}-(void)networkFetcher:(EOCNetworkFetcher*)fetcher didFailWithError:(NSError*)error {
   /* Handle error */


}@end

协议中的方法一般都是“可选的(optional)”。为了指明可选方法,委托协议经常使用@optional关键字来标注。

@protocol EOCNetworkFetcherDelegate
@optional
- (void)networkFetcher:(EOCNetworkFetcher*)fetcher didReceiveData:(NSData*)data;
- (void)networkFetcher:(EOCNetworkFetcher*)fetcher didFailWithError:(NSError*)error;
@end



如果在委托对象上调用可选方法,那么必须提前使用类型信息查询方法判断这个委托对象能否响应相关选择子,如下:

NSData *data = /*data obtained from network*/;
if ([_delegate respondToSelector:@selector(networkFetcher:didReceiveData:)]) {
   
	[_delegate networkFetcher:self didReceiveData:data];
}

这段代码调用了“respondsToSeclector: ”,来判断是否实现相关方法,如果返回false则不会进行任何操作。
delegate对象中的方法名也一定要起的恰当。方法名应该准确描述当前发生的事件以及delegate对象为何要获知此事件。此外,在调用delegate对象中的方法时,总是应该把发起委托的实例也一并传入方法中,这样,delegate对象在实现相关方法时,就能根据传入的实例分别执行不同的代码了。

- (void)networkFetcher:(EOCNetworkFetcher*)fetcher didReceiveData:(NSData*)data {
   
	if (fetcher == _myFetcherA) {
   
		/*Handel data*/
	} else {
   
		/*Handel data*/
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值