iOS Block

这篇文章是为了讲解ReactiveCocoa做的一个铺垫,由于ReactiveCocoa中大量使用Block,所以这里将对Block进行一个巩固,当然,Block用的很熟悉的朋友,大可不必看这篇文章。

在iOS4.0之后,Block面世,它是一种特殊的数据类型。它的本身是一段代码,特殊在于,它将这段代码当做了变量,然后通过类似block()这种方式回调。

写一个Block总共分几步?

答:三步!

  • 声明
    NSString *(^blockName)(NSString *str1, NSString *str2);
    从前到后依次为返回值类型、block名字、参数1、参数2
  • 定义
 (NSString *)^(NSString *str1, NSString *str2) {
        return [NSString stringWithFormat:@"%@+%@",str1, str2];
    };

注意:Block是一个语法块,后面我们要带“;”的!

  • 调用
    blockName(@"str1",@"str2");

根据传入参数和返回值类型,我们可以认为Block有四种类型:

  • 有参有返回值
//声明&定义
    NSString *(^block5)(NSString *) = ^(NSString *str){
        return [NSString stringWithFormat:@"%@+参数2", str];
    };
//调用
    NSLog(@"%@", block5(@"参数1"));
  • 有参无返回值
//声明&定义
    void (^block2)(NSString *) = ^(NSString *str){
        NSLog(@"%@", str);
    };
//调用
    block2(@"参数");
  • 无参有返回值
//声明&定义
    NSString *(^block4)(void) = ^(void){
        return @"返回值";
    };
//调用
    NSLog(@"%@", block4());
  • 无参无返回值
//声明&定义
    void (^block1)(void) = ^(void){
        NSLog(@"无参数 无返回值!");
    };
//调用
    block1();

Block的使用

在Block诞生之前,开发者们用的都是delegate来完成回调。在Block面世之后,绝大部分的回调处理被改为了Block。之所以做出这一改变,跟Block的使用简单,灵活等原因是分不开的!

这里我以再次封装AFNetworking为例,来对Block回调进行讲解。
先分析一下网络请求的几个必要要素:

  • 域名
  • 请求参数
  • 网络请求成功回调
  • 网络请求失败回调
  • 网络异常回调

这里面前两者没什么可分析的,主要说一下后三个Block的机制。
三者我们着重来讲解一个(网络请求成功回调),因为三者只是参数和返回的数据类型不一样,大同小异,只要理解了,没必要多做解释。

  • 通过typedef来给block起一个类型名称
typedef void (^ReturnValueBlock) (id returnValue);//成功回调
typedef void (^ErrorCodeBlock) (id errorCode);//失败回调
typedef void (^FailureBlock)();//错误回调

当我们要回调的时候,我们可以根据我们的参数类型、个数,和返回值类型来选择我们用哪种Block。
在网络请求的类中声明这个方法:

#pragma --mark POST请求方式
-(void) NetRequestPOSTWithRequestURL: (NSString *) requestURLString
                        WithParameter: (NSDictionary *) parameter
                 WithReturnValeuBlock: (ReturnValueBlock) block
                   WithErrorCodeBlock: (ErrorCodeBlock) errorBlock
                     WithFailureBlock: (FailureBlock) failureBlock;

方法中,我们传入的参数有三个Block,他们三个分别是用之前用typedef声明的,分别处理网络请求的时候不同的处理。接下来看看它是怎么实现的

#pragma --mark POST请求方式
-(void) NetRequestPOSTWithRequestURL: (NSString *) requestURLString
                        WithParameter: (NSDictionary *) parameter
                 WithReturnValeuBlock: (ReturnValueBlock) block
                   WithErrorCodeBlock: (ErrorCodeBlock) errorBlock
                     WithFailureBlock: (FailureBlock) failureBlock
{
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager POST:[NSString stringWithFormat:@"%@%@", BaseUrl, requestURLString] parameters:parameter progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"requestUrl: %@\nparameter: %@", requestURLString, parameter);
        if ([[responseObject objectForKey:@"status"] integerValue]== 200) {
            block(responseObject);
        } else if ([[responseObject objectForKey:@"status"] integerValue]== 400) {
            errorBlock(responseObject);
        }
    } failureObjc:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error, id responseObject) {
        NSLog(@"%@", responseObject);
        failureBlock();
    }];
}

主要看Success里面,这里面回调了两个block:”block“、”errorBlock“。不知道大家能不能看这两个block是在什么时候回调的。感觉应该可以看得懂,根据网络请求返回的状态,”200“表示网络请求成功,”400“表示网络请求失败,各家公司的接口应该都差不多吧。接下来就是使用了

由于这段代码是从公司工程中拿出来的,所以接口和数据的处理都被我删掉重新简化的写了下
-(void)getTeacherCommentLis{
    NSDictionary *dic = @{@"access_token":[USER_DEFAULT objectForKey:@"access_token"],
                          @"pageNo":[NSNumber numberWithInteger:1]};
    [[ZTAPIClient alloc] NetRequestPOSTWithRequestURL:@"getTeacherCommentLis" WithParameter:dic WithReturnValeuBlock:^(id returnValue) {
               网络请求成功,得到返回结果;
               可以刷新TableView,存储,更新等一系列操作
    } WithErrorCodeBlock:^(id errorCode) {
              网络请求失败,往往是填写的参数有问题
    } WithFailureBlock:^{
    }];
}

现在来想一想,回顾一下,以上的操作我们都是在做什么。我们是在哪里声明的block、又是在哪里定义的、最后又是在哪里调用的?

  • 在网络请求类的声明文件中,我们用typedef声明了block;
  • 在网络请求的方法中,我们把声明的block当做了参数,传入到了方法中
  • 在调用方法的时候,我们定义了这个block需要做的操作
  • 在网络请求类实现方法中,我们调用了block

Block相关的几个关键字

copy

block在使用的过程中跟对象一样会引起引用计数变化。同样声明block时,它的内存是分配在栈上,随时可能被回收,所以,我们需要将他拷贝到堆上。通过copy可以把block拷贝到堆上,来保证block不会被随时回收。
@property (nonatomic, copy)void(^block)(NSString *);

__block

在一个block里面,我们对block之外的变量是只读操作,也就是我们只能读取它的值,不可以更改。像这样,Xcode会给你报一个这样的错误。


block内访问外部变量.png

说到__block, 它是用于,我们想在block内来改变某个外部的变量的时候,我们需要在声明这个变量的时候用“__block”来修饰。


__block修饰外部变量
__weak

有时在使用block 的时候,由于self 是被强引用的,在 ARC 下,当编译器自动将代码中的block从栈拷贝到堆时,block 会强引用和持有self,而 self 也强引用和持有了 block,这就造成了循环引用,导致两者都不能释放,内存泄露。__weak解决循环引用的理念就是,将其中一者弱化,编程弱引用,也就是引用计数不会增加。 __weak修饰符修饰变量 self,让 block 不强引用 self,从而破除循环。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容