写高质量OC代码52建议总结:39.用handler块降低代码分散程度

来源:互联网 发布:淘宝云客服判断题 编辑:程序博客网 时间:2024/06/11 18:27

iOS系统上有个“系统监控器”,如果程序在一定时间内无响应,就会被自动终止。所以,在处理用户界面的显示及触摸操作所用的线程(主线程)不能因为要执行I/O或者网络通信这类耗时的任务而阻塞。

异步方法在执行完任务后,需要以某种手段通知相关代码。常用的手段是设计委托代理。当相关事件发生时就可以通知对象执行相关操作了。

#import <Foundation/Foundation.h>@class EOCNetworkFercher;@protocol EOCNetworkFetcherDelegate <NSObject>-(void)networkFetcher:(EOCNetworkFercher *)networkFetcher didFinishWithData:(NSDate *)data;@end@interface EOCNetworkFercher : NSObject@property (nonatomic, weak) id <EOCNetworkFetcherDelegate>delegate;-(id)initWithUrl:(NSURL *)url;-(void)start;@end
其他类可以使用此类的API

-(void)fetchFooData {    NSURL *url = [[NSURL alloc] initWithString:@"http://www.example.com/foo.dat"];    EOCNetworkFercher *fetcher = [[EOCNetworkFercher alloc] initWithUrl:url];    fetcher.delegate = self;    [fetcher start];}-(void)networkFetcher:(EOCNetworkFercher *)networkFetcher didFinishWithData:(NSDate *)data{    //  get data}
如果用块来改写的话,代码会更加清晰,开发者调用更加方便。

#import <Foundation/Foundation.h>@class EOCNetworkFercher;@protocol EOCNetworkFetcherDelegate <NSObject>-(void)networkFetcher:(EOCNetworkFercher *)networkFetcher didFinishWithData:(NSDate *)data;@endtypedef void (^EOCNetworkFetcherCompletionHandler)(NSData *data);@interface EOCNetworkFercher : NSObject@property (nonatomic, weak) id <EOCNetworkFetcherDelegate>delegate;-(id)initWithUrl:(NSURL *)url;-(void)start;-(void)startWithCompletionHandler:(EOCNetworkFetcherCompletionHandler)handler;@end
这和委托协议很像,不过多了个好处,在调用start方法时可以以内联形式定义completion handler。

-(void)fetchFooDataTwo {    NSURL *url = [[NSURL alloc] initWithString:@"http://www.example.com/foo.dat"];    EOCNetworkFercher *fetcher = [[EOCNetworkFercher alloc] initWithUrl:url];    [fetcher startWithCompletionHandler:^(NSData *data) {        //  get data    }];}
委托模式有两个缺点,如果类要使用多个获取器下载不同数据。就需要在代理方法中判断获取器的类型以处理不同的数据。

-(void)networkFetcher:(EOCNetworkFercher *)networkFetcher didFinishWithData:(NSDate *)data{    if (networkFetcher == /*....*/) {        //  data....    } else if (networkFetcher == /*....*/) {        //  data....    }}
这么写代码不稳定性很高,而且会很快使代码量激增。改用块来处理的好处是:无需监听获取器,也无需在监听方法中判断获取器。

-(void)fetchFooDataThree {    NSURL *url = [[NSURL alloc] initWithString:@"http://www.example.com/foo.dat"];    EOCNetworkFercher *fetcher = [[EOCNetworkFercher alloc] initWithUrl:url];    [fetcher startWithCompletionHandler:^(NSData *data) {        //  get data    }];    NSURL *urlTwo = [[NSURL alloc] initWithString:@"http://www.example.com/foo.dat"];    EOCNetworkFercher *fetcherTwo = [[EOCNetworkFercher alloc] initWithUrl:urlTwo];    [fetcherTwo startWithCompletionHandler:^(NSData *data) {        //  get data    }];}
这种写法还有别的用处,现在很多基于块的API被用来处理错误。可以用两个块来分别处理成功和失败两种情况。也可以把成功和失败的处理都放在一个块中。

typedef void (^EOCNetworkFetcherCompletionHandler)(NSData *data);typedef void(^EOCNetworkFetcherErrorHandler)(NSError *error);@interface EOCNetworkFercher : NSObject@property (nonatomic, weak) id <EOCNetworkFetcherDelegate>delegate;-(id)initWithUrl:(NSURL *)url;-(void)start;-(void)startWithCompletionHandler:(EOCNetworkFetcherCompletionHandler)handler;-(void)startWithCompletionHandler:(EOCNetworkFetcherCompletionHandler)handler failureHandler:(EOCNetworkFetcherErrorHandler)failHandler;@end
-(void)fetchFooDataFour {    NSURL *url = [[NSURL alloc] initWithString:@"http://www.example.com/foo.dat"];    EOCNetworkFercher *fetcher = [[EOCNetworkFercher alloc] initWithUrl:url];    [fetcher startWithCompletionHandler:^(NSData *data) {        //  get data    } failureHandler:^(NSError *error) {        //  get error    }];}
总结:

1.在使用对象时,可以使用内联的handler块将相关业务逻辑一起声明。
2.在有多个对象需要监控时,代理模式的实现中需要判断对象。用块实现,可以直接将块与关联对象链接。
3.设计API时可以增加一个参数,调用者通过该参数来决定应该把块安排在那个队列上执行。


阅读全文
0 0
原创粉丝点击