码迷,mamicode.com
首页 > 其他好文 > 详细

《Effective Objective-C 2.0》—(第23-28条)—类别、协议,代理,匿名对象、delegate

时间:2014-08-10 15:45:00      阅读:299      评论:0      收藏:0      [点我收藏+]

标签:协议   代理   匿名对象   

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

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

        此模式可以将数据与业务逻辑解耦。

        在Objective-C中,一般通过“协议”这项语言特性来实现此模式,整个Coco系统框架都是这么做的。如果你的代买也这样写,那么就能和系统框架很好地融合在一起了。

        举例:

回调委托对象的流程。请注意,“委托对象”未必非得由EOCDataModel实例来担任不可,也可以由另外一个对象扮演此角色

bubuko.com,布布扣

        利用协议机制,很容易就以Objective-C代码实现此模式,代码如下:

@protocol EOCNetworkFetcherDelegate
-(void)netWorkFetcher:(EOCNetworkFetcher*)fetcher didReceiveData:(NSData*)data;//这个EOCNetworkFetcher*参数可以高速委托对象,是谁调用它的
-(void)netWorkFetcher:(EOCNetworkFetcher*)fetcher didFailWithData:(NSError*)error;
@end

有了这个协议之后,类就可以用一个属性来存储委托对象了。在本例中,这个类就是EOCNetworkFetcher类:

@interface EOCNetworkFetcher :NSObject
@property (nonatomic,weak) id<EOCNetworkFetcherDelegate> delegate;
@end

一定要注意这个属性定义成weak,而非strong。因为两者之间必须为“非拥有关系”。如下图所示:

bubuko.com,布布扣

为了避免循环引用,NetWorkFetcher不保留delegate属性.

看一下EOCDataModel的实现:

@interface EOCDataModel()<EOCNetworkFetcherDelegate>
@end
@implement EOCDataModel
-(void)netWorkFetcher:(EOCNetworkFetcher*)fetcher didReceiveData:(NSData*)data{
if(fetcher == _myFetherA){
/* handle data*/
}else if(fetcher == _myFetherB){
/* handle data*/
}
}
-(void)netWorkFetcher:(EOCNetworkFetcher*)fetcher didFailWithData:(NSError*)error{
/*handle error*/
}
@end

这个EOCNetworkFetcher*参数可以高速委托对象,是谁调用它的.

下面是EOCNetworkFetcher调用情况

NSData *data = /*data obtained from network*/
if([_delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)]){
[_delegate networkFetcher:self didReceiveData:data];
}
通过这个例子,大家应该很容易理解此模式为何叫做“委托模式”:因为对象把应对某个行为的责任委托给另外一个类了。

关于运行时刻,每次都判断respondsToSelector:@selector(xxxx)是多余的,只有第一次判断是有用的参考优化办法
【本节要点】

● 委托模式为对象提供了一套接口,使其可由此相关事件告知其他对象。

● 将委托对象应该支持的接口定义成协议,在协议中把可能需要处理的事情定义成方法

● 当某对象需从另一个对象中获取数据时,可以使用委托模式。这种情境下,该模式亦称为“数据源协议”(data source protocal)

● 若有必要,可实现还有位段的结构体,将委托对象是否能够相应相关协议方法这一信息缓存至其中。

第24条:将类的实现代码分散到便于管理的数个分类之中

    类中经常容易填满各种方法,而这些方法的代码则全部堆在一个巨大的实现文件里。在此情况下,可以通过Objective-C的“分类”机制,把类代码按照逻辑划入几个分区中。

Cocoa中的NSURLRequest类以及可变版本NSMutableURLRequest类就是这么做的。

另外:在编写准备分享给其他开发者使用的程序库时,可以考虑建立“Private”分类,如果程序中的某个地方要用到这些方法,那就引入此分类的头文件。而分类头文件并不会随程序库一并公开,于是该库的使用者也就不知道库里还有这些私有方法了。

第25条:总是为第三方类的分类名称前加前缀

    分类机制通常用于向无源码的既有类中添加新功能。这个特性极为强大,但是使用时候很容易忽视产生的问题。分类中的方法是直接添加到类里面的,如果分类中的方法跟类中本来就有的方法重名了,那么就会覆盖掉固有的方法了。

你可能这么写分类

@interface NSString (HTTP)
//Encode a string with URL encoding
-(NSString*)urlEncodeString;
//Decode a URL encoded string
-(NSString*)urlDecodedString;
@end

如果NSString类本身就有urlEncodeString方法,或者还有另外一个分类也叫urlEncodeString,如果别人写的分类加载时间比你晚的时候,你的将被覆盖。想要解决此问题,以命名空间来区分各个分类的名称

@interface NSString (ABC_HTTP)
//Encode a string with URL encoding
-(NSString*)abc_urlEncodeString;
//Decode a URL encoded string
-(NSString*)abc_urlDecodedString;
@end

第26条:勿在分类中生命属性

属性是封装数据的方式。尽管从技术上说,分类里可以生命属性,但这种做法还是要尽量避免。

第27条:使用“class-continuation”隐藏实现细节

(待补充)

第28条:通过协议提供匿名对象

    协议定义了一系列方法,遵从此协议的对象应该实现它们。于是,我们可以用协议把自己写的API之中的实现细节隐藏起来,将返回的对象涉及位遵从此协议的纯id类型。这样的话,想要隐藏的类名就不会出现在API之中了。
此概念经常称为:“匿名对象”(anonymous object),这与其他语言的“匿名对象”不同。
@property (nonatomic,weak)id<EOCDelegate> delegate;
由于该属性的类型是id<EOCDelegate>,所以实际上任何类型的对象都能充当这一属性,即便该类不继承自NSObject也可以,只要遵循EOCDelegae协议就行。
NSDictionary也能实际说明这一概念,在字典中,键的标准内存管理语义是“设置时拷贝”,而值的语义是“设置时保留”。因此在可变版本的字典中,设置键值对所用的方法的签名是:
-(void) setObject:(id)object forKey:(id<NSCopying>)key;
表示键的哪个参数类型位id<NSCopying>,作为参数值的对象,它可以是任意类型,只要遵从NSCopying协议就好,这样的话,就能向该对象发送拷贝消息了。这个key参数可以视为匿名对象。与delegate一样
    数据案例,数据库连接(database connection)的程序也用这个思路,以匿名对象来表示从另一个库中返回的对象。对于处理连接哪个类,你也许不想让万人知道。如果没有办法令其继承字同一个基类,那么就得返回对下你跟遵从此协议:
@protocol EOCDatabaseConnection
-(void) connect;
-(void)disconnect;
-(void)isConnected;
-(NSArray*)performQuery:(NSString*)query;
@end;
然后,就可以用“数据库处理器”单例来提供数据库连接了。这个单例的接口可以写成:
@protocol EOCDatabaseConnection
@interface EOCDatabaseManger:NSObject
+(id)sharedInstance;
-(id<EOCDatabaseConnection>) connectionWithIdentifier:(NSString*)identifier;
@end;
这样的话,处理数据库连接所用的类名称几UI不会泄露了。
    有时对象类型并不重要,重要的是对象有没有实现某些方法。在次情况下,也可以是使用“匿名类型”(anonymous type)来表达这一概念。
    CoreData框架里也有这种用法。查询CoreData数据库所得的结果由名叫NSFetchedResultsContrller的类来处理,如果有需要,处理时还会把数据分区。在负责处理查询结果的控制器中,有个section属性,用以表示数据分区。此属性是个数组,但其中的对像没有指明具体类型,只是说这些对象遵从了NSFetchedResultsSectionInfo协议。下面代码通过控制器来获取数据分区信息:
NSFetchedResultsController * controller = /*some controller*/;
NSUInteger section = /*section index to query*/
NSArray *sections = controller.sections;
id<NSFetchedResultsSectionInfo> sectionInfo = sections[section];
NSUInteger numberOfObjects = sectionInfo.numberOfObjects;
sectionInfo 是个匿名对象。
【本节要点】
● 协议可在某种程度上提供匿名类型。具体的对象类型可以淡化成遵从某协议的id类型,协议里规定了对象所应实现的方法。
● 使用匿名对象来隐藏类型名称(或类名)
● 如果居室类型不重要,重要的是对象能够响应特定方法,那么可以是使用匿名对象来表示。

《Effective Objective-C 2.0》—(第23-28条)—类别、协议,代理,匿名对象、delegate,布布扣,bubuko.com

《Effective Objective-C 2.0》—(第23-28条)—类别、协议,代理,匿名对象、delegate

标签:协议   代理   匿名对象   

原文地址:http://blog.csdn.net/hherima/article/details/38399749

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!