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

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;
@end

typedef 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时可以增加一个参数,调用者通过该参数来决定应该把块安排在那个队列上执行。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值