Block使用详解,Block与代理相比的优点与缺点

来源:互联网 发布:中国m2数据 编辑:程序博客网 时间:2024/05/15 08:16

Block是iOS4.0+ 和Mac OS X 10.6+ 引进的对C语言的扩展,用来实现匿名函数的特性。
Block是Apple Inc.为C、C++以及Objective-C添加的特性,使得这些语言可以用类lambda表达式的语法来创建闭包。
闭包就是能够读取其它函数内部变量的函数。就是在一段请求连续代码中可以看到调用参数(如发送请求)和响应结果。所以采用Block技术能够抽象出很多共用函数,提高了代码的可读性,可维护性,封装性。
不像代理声明了一个代理函数,在调用的类内部还要实现该函数,让人莫名惊诧,若一个页面能发送多个请求,并且用多点触控同时触发发送多个请求,那个这个页面的代理函数很难区分是那个请求的结果,胡乱解析消息很容易崩溃。有人说我发送一个请求就起个菊花,消息不返回,不让发其他请求。告诉你这个行不通,原因是弹出菊花是起一个线程,调用起线程很快会返回成功,但是你起的线程被加入主线程并且实际运行起来是需要时间的,大约需要130毫秒,并且那个提示菊花提示框也是刷新UI线程才出来的。所以当你两个手指同时点击两个发送请求或切换也页面的按钮时,在当点吉第一个按钮并起菊花,但是在菊花出现前的点击了另一个按钮时,那么你就连续发送了两个请求了。那么你用代理实现时就很难分出那个消息,只有你的响应消息中带有消息类型可能会分出来,若服务器做的不够强大,当出现异常时,找不发送请求,给你来个通用错误响应消息,你只有傻眼了。这样多个消息在一个函数里解析也不利于封装。
综上所述:Block就是把你发送的请求和响应放在一块,配成一对,所以又叫代码块嘛。
Block的优点是能把发起的部分和响应的部分放在一起,可以很容易的理解和处理。
缺点是若你的响应部分处理不当,若多次返回,那么你的代码会乱套;若你返回时返回错误返回了其它的代码块就会出现跑到其它流程里面去;最严重的是若代码永远不返回,那么你的程序又是根据返回结果跳转页面的,那么你永远停留在原页面,并且会造成内存不能释放,谁让你扮演红娘失败呢!
举个实际的例子,我发送下线请求,由于代码写的有问题,导致在长连接线程里返回的上线成功的BLOCK,结果导致程序走入上线流程里了(上线BLOCK处理部分)。
代理也有其优点和适用场景:代理在自定义控件方面具有其绝对的优势。如:你想定义一个显示无网络信息的标签和一个按钮,当你点击按钮时进行操作(切换检查的网络地址,IOS自带的网络检查是连接到苹果服务器域名。点击按钮时你可以检查你服务器的域名)域名来最终显示或隐藏这个图层,那么这个图层可以抽象成一个控件,这个控件的响应函数就用代理函数来实现。以前我的文章介绍的小气泡的控件实现方法也是用代理实现了。
适合代理实现的方法有一个显著的特点,只需要处理响应(如:按钮响应事件),没有或不考虑发起者。代理方法在自定义控件上大展宏图。
适合BLOCK的显著特点,有明确的发起方和响应方,两者能配对需要紧密联系。如:网络请求。
BLOCK最典型的是大所周知的AFNETWORK第三方库。它能解决发送函数找到自己对应的响应消息。代理方面的典型例子见我的文章《自己实现异步发送请求和图片》:http://blog.csdn.net/jia12216/article/details/47043935。

BLOC首先你在.h文件中声明BLOC对象,当然返回的参数你可以自己定义:
typedef void (^RequestCompletionBlocks)(NSDictionary *result,BOOL successed);
typedef void (^SocketLineSuccessBlocks)(BOOL successed);
typedef void (^SocketLineFailedBlocks)(BOOL successed);

@property (nonatomic,weak) RequestCompletionBlocks myblock; //block返回参数
@property (nonatomic,weak) SocketLineSuccessBlocks socktlineSuccessBlock; //成功连接
@property (nonatomic,weak) SocketLineFailedBlocks socktlineFailedBlock; //失败连接

注意:若你的block是在另一个子线程里返回,那么你不能用weak或assign,要用strong声明,不然走的是作死的路。当然你在通知里返回或在其它主线程里返回,你用weak,内存更安全。
如:

@property (nonatomic,strong)  RequestCompletionBlocks myblock; //block返回参数@property (nonatomic,strong)  SocketLineSuccessBlocks socktlineSuccessBlock; //成功连接@property (nonatomic,strong)  SocketLineFailedBlocks socktlineFailedBlock; //失败连接

-(void)socketConnectHost:(SocketLineSuccessBlocks)onSuccesscpmlention
failCompltion:(SocketLineFailedBlocks)onfailCompltion// socket连接

在.m文件中实现该函数就可以了
// socket连接
-(void)socketConnectHost:(SocketLineSuccessBlocks)onSuccesscpmlention
failCompltion:(SocketLineFailedBlocks)onfailCompltion// socket连接
{
//这个存储发送请求对象和响应请求对象到全局变量中
self.socktlineSuccessBlock = onSuccesscpmlention;
self.socktlineFailedBlock = onfailCompltion;
//这个是调用了另一个BLOCK函数
[[checkReachability sharedCheckReachability] checkReachability:^(NetworkStatus status) {
if (status == NotReachable)
{
//无网络返回失败
onfailCompltion(NO);
}
else
{
self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];

        NSError *error = nil;        [self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:-1 error:&error];        //请求响应的成功消息在另一个socket线程函数里返回    }}];

}

//请求响应的成功消息在socket线程函数里返回

pragma mark - 连接成功回调

  • (void)socket:(GCDAsyncSocket )sock didConnectToHost:(NSString )host port:(uint16_t)port
    {
    //后台也能用
    // [self.socket performBlock:^{
    // self.socket.enableBackgroundingOnSocket = YES;
    // }];
    NSLog(@”socket连接成功”);
    STATUS = Socketonline;
    self.socktlineSuccessBlock(YES);

    self.readhead = YES;
    [self.socket readDataToLength:10 withTimeout:-1 tag:1];

}

BLOCK函数的调用大家都知道吧:
// 服务器掉线,重连
[self socketConnectHost:^(BOOL successed) {
if(successed)
{
//服务返回成功时的处理
}
else
{
//服务器返回的处理失败的处理
}

        } failCompltion:^(BOOL successed) {             //异常时的处理,通常指非服务器返回的异常        }];
0 0