block详解

本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看。

基本概念

Block可以帮助我们组织独立的代码段,并提高复用性和可读性。

Block的好处,我总结了下主要有2点:1.用于回调特别方便,2.可以延长对象的作用区域。

为了性能,默认Block都是分配在stack(栈)上面的,所以它的作用区域就是当前函数。

int main()
{
    int i = 1024;
    void (^blk)(void) = ^ {
        printf("%d\n", i);
    };
    blk();
    return 0;
}

main函数执行完毕后,blk这个block就销毁了。

Block具有将临时函数体创建为表达式的优势。Apple文档中指出: 
Block是符合如下要求的匿名内联的代码集:

  • 和函数一样具有一个指定类型的参数列表
  •  有一个可以推导或声明的返回值类型
  • 可以从它被定义的词义范围中捕捉状态
  • 可以在需要的时候改变词义范围的状态
  • 可以和相同的词义范围中定义的其他的Block共享更改的可能。
  • 可以在词义范围(堆栈帧)被销毁后继续共享和修改该词义范围(堆栈帧)的状态。

Block是一个自包含的小代码段,封装了用于遍历(线性遍历)或者回调,可以并发执行的任务单元。


int (^oneFrom)(int) = ^(int anInt) {  
    return anInt - 1;  
};  
// 我们创建了一个内联块^(int anInt)... ,其函数体和结果被传到了另外一个名为OneFrom的Block。  
 
printf("1 from 10 is %d", oneFrom(10));  
// 打印出: "1 from 10 is 9"  
// 这个block函数(distanceTraveled)传入3个float型参数,返回float值。   
 
float (^distanceTraveled) (float, float, float) =  
 
                          ^(float startingSpeed, float acceleration, float time) {  
    float distance = (startingSpeed * time) + (0.5 * acceleration * time * time);  
    return distance;  
}; 

用clang命令分析block对外部变量的处理

Example:

// block中如果想访问外部变量,那么变量必须用 __block 进行修饰
__block int i = 10;
void (^testBlock)() = ^(){
    i++;
};
        
testBlock();
        
NSLog(@"i现在的值:%d",i);

上例中的结果为11,那究竟是进行怎样的传值工作呢? 我们可以使用clang指令,查看生成的cpp文件。

假设上面代码是在main.m文件中,那么打开终端,

1. cd main.m文件所在的具体物理路径

2. clang -rewrite-objc main.m 

3. open main.cpp


block部分生成的C++代码如下:

void (*testBlock)() = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_i_0 *)<span style="font-size:24px;color:#cc0000;"><strong>&i</strong></span>, 570425344);


注意红色标注的地方,block内部对变量i进行的是地址操作,所以结果就一目了然了。


block在UI具体操作中的使用

对上图进行大致的说明:

1. 左侧的图,是网易新闻结构图(左边LeftViewController是板块列表:新闻,本地... ; 右边则是具体板块的详细信息)

2. 中间的图,是在LeftViewController中自定义的block,点击不同的板块,均会调用leftBlock,只是block的输入参数为不同的板块信息而已。

3. 右侧的图,板块的详细信息(MainViewController),负责每个板块具体信息的展示工作


block的内存分析(下面一张图,我详细的剖析了block为什么要使用copy策略及解除循环引用的问题)


block中的循环引用

上图中,我大致介绍了block在MRC下循环引用。这里,我再具体详细说明一下block的循环引用问题

self.completionBlock = ^ {
        if (self.success) {
            self.success(self.responseData);
        }
    }
};

上面的代码中 self 对 completionBlock 这个block进行了强引用,而 completionBlock 内部又对 self 进行了强引用,最终会导致内存释放不掉。 解决的思路便是: 有一方应该变成若引用,oc中已经提供了关键字__weak。 所以实现代码如下:

__weak typeof(self) weakSelf = self;
self.completionBlock = ^ {
    if (weakSelf.success) {
        weakSelf.success(weakSelf.responseData);
    }
};

总结:这一节,我对block的使用,原理,注意点进行了一一说明,下一节谈谈 delegate及notification的使用及注意点。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋恨雪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值