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

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

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

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

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

举例:

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

利用协议机制,很容易就以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。因为两者之间必须为“非拥有关系”。如下图所示:

为了避免循环引用,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

时间: 2024-10-25 11:09:10

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

[Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+1}" 反射获取函数源代码的功能很强大,使用函数对象的toString方法有严重的局限性.toString方法的局限性ECMAScript标准对函数对象的toString方法的返回结果(即该字符串)并没有任何要求.这意味着不同的js引擎将产生不同的字符串,甚至产生的字符串与该函数并不相关. 如果函数

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

协议定义了一系列的方法. id类型将类的类型隐藏起来了,可以有多个不同的实现类.只在运行期才查出些对象的实际类型 可以用协议把API之中的实现细节隐藏起来,将返回的对象设计为遵从此协议的纯id类型(也叫“匿名类型”).这个概念就称为“匿名对象”(anonymous object). 例: @property(nonatomic, weak) id<EOCDelegate> delegate;  // 1.用于属性 -(void)setObject:(id)object forKey:(id&l

effective OC2.0 52阅读笔记(四 协议与分类)

23 通过委托与数据源协议进行对象间通信 总结:委托模式的常规委托模式中,信息从类Class流向受委托者delegate.数据源模式,信息从数据源datasource流向class.数据源和受委托者可以是两个不同对象.有时候一个可选择方法可能在一个生命期中多次调用,如果每次都检查委托对象是否能响应选择子,那就显得多余了.可以使用位段(bitfield)数据类型将方法响应能力缓存起来. 24 将类的实现代码分散到便于管理的数个分类之中 总结:易于管理,便与调试.将应视为“私有”的方法归入名为Pri

传智播客 刘意_2015年Java基础视频-深入浅出精华版 笔记(2015年10月25日23:28:50)

本笔记是个人笔记+摘录笔记相结合,非完全原创 day01 win 7系统打开DOS有趣方法:按住shift+右键,单击“在此处打开命令窗口”(注意:在此处可以是任何的文件夹,不一定是桌面) 用DOS删除的文件不可以在回收站恢复?!! 常用DOS命令d: 回车 盘符切换dir(directory):列出当前目录下的文件以及文件夹md (make directory) : 创建目录(创建文件夹)rd (remove directory): 删除目录(删除文件夹,注意:前提是文件夹必须是空的!!)如果

《Effective Objective-C 2.0》—(第1-5条)—熟悉Objective-C

Objective-C通过一套全新的语法,在C语言基础上添加了面向对象特性.OC的语法中频繁使用中括号([  ]),而且不吝于写出极长的方法名,这通常令许多人觉得此语言较为冗长.这是这样写出来的代码非常易读,只是C++和Java程序员不太适应. OC语言学起来很快,但有很多微妙细节需要注意,而且还有许多容易为人所忽略的特性.另一方面,有些开发者并未完全理解或是容易滥用某些特性,导致写出来的代码难以维护,难以调试.本章讲解基础知识,后续各章语言及其相关架构的各个特定话题. 第1条:了解OC语言的起

Effective C++:条款28:避免返回 handles 指向对象内部成员

(一) 有时候为了让一个对象尽量小,可以把数据放在另外一个辅助的struct中,然后再让一个类去指向它.看下面的代码: class Point { public: Point(int x, int y); void setX(int newVal); void setY(int newVal); }; struct RectData { Point ulhc; Point lrhc; }; class Rectangle { public: Point& upperLeft() const {

sudo: effective uid is not 0, is sudo installed setuid root

当普通用户需要临时使用root权限的时候需要执行sudo命令,但是在执行sudo命令的时候需要使用root的权限去执行/usr/bin/sudo二进制文件. 如果报错出现sudo: effective uid is not 0, is sudo installed setuid root 证明/usr/bin/sudo文件没有设置s权限(用户在执行文件的时候,临时拥有文件所有者的权限.) 解决方法: chmod u+s /usr/bin/sudo 加上权限之后再查看文件 ll  /usr/bin

iOS开发——技术精华Swift篇&amp;Swift 2.0和Objective-C2.0混编之第三方框架的使用

Swift 2.0和Objective-C2.0混编之第三方框架的使用 swift 语言是苹果公司在2014年的WWDC大会上发布的全新的编程语言.Swift语言继承了C语言以及Objective-C的特性,且克服了C语言的兼容性问题.Swift语言采用安全编程模式,且引入了多种新功能,使得编程工作更加简便,灵活! 2015年6月9日苹果又一次给所有开发之者带来了一个惊喜,那就是今年年底swift讲开源,者队iOS开发着来说无疑是一个值得兴奋的消息,可是就在这短短的几个月里面swift吸引了越来

MyCCL复合特征码定位系统3.0 build 23 中文绿色版

MyCCL复合特征码定位系统介绍 这是一个主要定位木马病毒的特征码的工具. MYCCL是CLL的改进版,可以进行多重特征码的定位,针对金山等杀软的反向定位等功能,并实现自动化代码定位和显示. myccl是定位特征码用的,定位完得你手动修改 最好是先用OC转换为内存地址,然后再用OD加载,修改特征码,这样容易点. MyCCL复合特征码定位系统介绍 MyCCL3.0.7z 解压密码:xiaochina 烈焰下载:http://pan.baidu.com/s/1bnCh2LD MyCCL复合特征码定位