Delegation ,Block,NSNotification

1.delegation:
Delegation 是一种很清晰回调形式,从 Protocol 的建立,到之后的引用,和对于 delegate 声明的变量处理,都非常具有条理。建立完 Delegation 之后,其他方法在调用的时候会很清晰整个回调的流程和处理。在处理一些延迟回调或者触发回掉的时候,声明调用的类里面的回调方法在编写时可以按照很独立的逻辑在制作。在使用 Delegation 的时候,一个回调方法可以对应多个不同的 Delegation ,这不仅简化了编程过程,也让能回调处理更加清晰。
Delegation 不好的地方在于,在类中调用 delegate 方法的时候,需要对 delegate 本体进行一定的验证核对,防止出现方法对象为空的情况,再一个就是受制于 performSelector 这个 selector 方法,回掉返回的参数被限制在了 NS 类的范围内,数量也很有限(当然可以用直接调用方法的形式在绕过,并不推荐;也可以用 Array 套着传, 不过这样需要有文档支持,不然不够清晰,回调方法也需要独立的验证,故也不推荐):
if (self.delegate && [self.delegate respondsToSelector:@selector(ABC:)]){
[self.delegate performSelector:@selector(ABC:) withObject:@"ABC"];
}
//需要验证代理是否为空,同时验证代理方法是否存在
这个问题在 Swfit 中有了很不错的解决:
delegate?.ABC?(@"ABC")
至于说 Delegation 的另外一个问题,那就是使用了 Delegation 之后,代码阅读变成了一件很困难的事情,你需要在不同的 Class 文件中一次次的跳转来理解整个代码思路,要知道糟糕的 XCode 还经常会跳错方法(Command + 点击跳转,跳到了同名的其他方法),导致代码可读性的下降。要说的话,这一点在 Swift(2.2)版本中有一定的优化,不过 Swift 的 Selector 还在修正中,之后也许会在对于 Delegation 的可读性上做更多的优化。
最后一个比较核心的问题就在于,在一批变量声明了代理之后,在代理回掉被执行时,你是不太好知道这个变量究竟是这一批中的哪一个的。这也就是为什么苹果在制作 delgate 和 datasource 的时候都会在代理方法的返回值中带上声明代理类本身的原因。
2.block:
Block 是一种很好用的回掉方式,其解决了 Delegation 在确认声明对象上的问题,由于 Block 回调方法一般都跟随在声明之后,所以可以很快确认回调来源,通过 __block 声明的变量也可以很方便的穿越到回调方法中进行使用,代码可读性上,一般来说使用 Block 的代码比使用 Delegation 的代码可读性更强(当然你也可以声明 Block 回调方法对应变量,然后按照和 Delegation 差不多的方法来调用他)。
Block 的缺陷主要就在于使用 ARC 情况下的循环引用。从某种程度上来说, Block 回调的方法内变量实际上是关联在声明 Block 的类里面的,但 Block 回调方法本身是在使用 Block 的类中的,同时使用类的 self 本身是可以在 Block 回调方法中被请求的,这里就会出现使用类 A 引用声明类 B ,B 在关联的 Block 中又引用了使用类 A ,这样一个循环之后引用可以无限循环下去,在这种无限循环的引用下, ARC 就无法知道 A 和 B 的确切弃用时间,所以 A 和 B 会在内存中永远存活下去,直到进程被消灭。所以,在很多时候,我们必须要使用 __weak 来声明一个 weakself ,来帮助 ARC 判断内存回收的时间。
这里要指出的是, Block 的回调方法也是可以复用,创建回调方法这一套东西在 Objective-C 中是继承于 C 样式的,一般来说,这个东西是没人用。[4]
void (^simpleBlock)(id responseObject) = ^(id responseObject){
NSLog(@"This is a block");
};
//这里创建了 simpleBlock 之后就可以像 Delegation 回调方法那样在各种回调声明中使用了

3.nsnotification;
NSNotification 本身是一个非常强大的回调,因为他的回调是全局而且一对多的,广播的特性使得很多时候使用 NSNotification 能一次解决大面积的问题。
至于说 NSNotification,就和上面说到的一样,也主要是在于他的全局广播属性和权限机制。
在使用 NSNotification 的时候,注册完回调方法之后,开发者需要自行对注册进行取消操作。比如说你注册一个 A 方法到 B 通知,由于某些原因 A 方法所在的类被 ARC 回收掉了,那么在 B 通知被触发的时候,由于 A 的通知注册信息还在,就会出现调用了非法的内存地址的情况。
至于说 NSNotification 的权限问题,对于写类的人来说是比较头疼的,很多时候只能靠文档和调用者的自觉,出于权限考虑,如果不是特别需求全局广播这个特性,一般不太建议使用 NSNotification。
NSNotification 由于自身的限制,在回调可以传递的内容上也存在数量和内容的限制,虽然可以通过 Array 的方法绕过,但这样在代码可读性就会有折扣,对于文档也需要有要求,回调方法中还需要验证。

4如何选择使用三者;
对于初级的开发人员来说,关键在于使用习惯。如果你从其他语言转到 Objective-C 或者 Swift ,相信 Delegation 肯定让你觉得更加亲切,那么在初级阶段请使用好这个语法糖,多用,多去理解;如果你用着 AFNetworking 看着其他老前辈的说法用 Block 觉得效率很高很开心,那就开心的用,直到你被循环引用烦到了为止(笑);如果你用 NSNotification ……你还是别用了。然后,在你代码写多了之后,你可以开始尝试接触其他回调方式,去感受这些回调方式的不同。

对于中级的开发人员,关键在于对于回调流程的理解。
你要知道你的回调是一个什么性质的回调,如果这个回调是一个不定期触发,或者会多次触发的,那么 Delegation 应该更适合;如果这个回调是一个一次性的,并且和调用方法是单线性关系的,那么 Block 应该更适合;如果这个回调是广播性质的,需要很多个不同的类都接收到,那么 NSNotification 更适合。
在不同的执行线(不是线程),不同的执行次数、执行数量上的区别,是鉴别使用哪一种回调的最好判断方法。
对于 Block 来说,他的执行线应该是和调用方法、回调方法连续在一起的;对于 Delegation 和 NSNotification 来说,他的执行线可以是连续的,也可以是调用方法和回调方法之间有很长的间隔,或者说回调方法在执行线上会多次出现。

你可能感兴趣的:(Delegation ,Block,NSNotification)