本文介绍: 本章的内容是比较麻烦复杂的一章,牵扯到了GCD和Block,在之前也有学习过,本章作以深入的了解多线程问题是开发应用程序的时候最让人头疼的问题,尤其是线程阻塞,在更新了Mac之后我经常的遇到了彩虹小球的问题,当然在开发的时候还没有出现过线程阻塞问题。Apple以块和大中枢派发设计了全新的多线程,也就是block和GCD。这是两种不同的技术,但都是一并引入的。块:这个机制方便我们把代码像对象一样传递,令其在不同的环境下运行,而且在定义块的范围内可以访问其中的全部变量。
前言
- 本章的内容是比较麻烦复杂的一章,牵扯到了GCD和Block,在之前也有学习过,本章作以深入的了解
- 多线程问题是开发应用程序的时候最让人头疼的问题,尤其是线程阻塞,在更新了Mac之后我经常的遇到了彩虹小球的问题,当然在开发的时候还没有出现过线程阻塞问题。
GCD和块的简介
37.理解块的概念
块的基础知识
^{
block implementation
}
return_type (^block_name)(parameters)
NSString* (^addBlock)(NSString *a, NSString *b) = ^(NSString *a, NSString *b) {
return [NSString stringWithFormat:@"%@%@", a, b];
};
块可以捕获变量
NSString *c = @"ff";
NSString* (^addBlock)(NSString *a, NSString *b) = ^(NSString *a, NSString *b) {
return [NSString stringWithFormat:@"%@%@%@", a, b, c];
};
- 当然在默认情况下我们捕获的C字符串是不可以修改的,不过声明变量的时候加入_block即可在块内修改
- 第一次使用出现了错误 记录一下, 我把这个属性定义到了属性声明的位置,接下来放到内部实现局部变量即可
__不允许块属性,仅允许在局部变量上 __block attribute not allowed, only allowed on local variables
内联块的用法
- 如果块所捕获的变量是对象类型,那么就会自动保留它。系统在释放这个块的时候,也会将其一并释放。这就引出了一个于块有关的重要问题。块本身可视为对象。并且块本身也和其他对象一样,有引用计数
- 如果将块定义在OC类的实例方法中,那么除了可以访问类的所有实例变量之外,还可以使用self变量。块总能修改实例变量,所以在声明时无需加_block。不过,如果通过读取或写入操作捕获了实例变量,那么也会自动把self变量一并捕获了,因为实例变量是与self所指代的实例关联在一起的。也就是说,只要你在块中调用到了属性值,那么这个块就会捕获这个类本身也就是self。
块的内部结构
- OC对象都会占用某个内存区域,块本身也是对象,也存在内存区域和内存布局
- 在存放块对象的内存区域中,首个变量是指向Class对象的指针,该指针叫做
isa
- 在内存布局中,最重要的就是
invoke
变量,这是个函数指针,指向块的实现代码。函数原型至少需要接受一个void*
型的参数,此参数代表块,这其实就是一种代替函数指针的语法结构,把函数通过块封装成有用的接口 descripto
r变量是指向结构体的指针,每个块里都包含此结构体,其中声明里块对象的总体大小,还声明里copy与dispose
这两个辅助函数所对应的函数指针。- 块还会把它所捕获的所有变量都拷贝一份。这些拷贝放在
descriptor
变量的后面,捕获了多少个变量,就要占据多少内存空间。拷贝的并不是对象本身,而是指向这些对象的指针变量。 - invoke函数为何需要把块对象作为参数传进来呢?因为要从内存中把这些捕获到的变量读出来
全局块,栈块,堆块
堆块
全局块
除了“栈块”和“堆块”之外,还有一类块叫做“全局块”。这种块不会捕捉任何状态(比如外围的变量),运行时也无须有状态来参与。而且全局块的copy属于空操作。可以把他认为是单例。
要点
38.为常用的块类型创建typedef
typedef int (^EOCSomeBlock)(BOOL flag, int value);
如此以来与定义其他变量时一样,变量类型在左边,变量名在右边。
要点
- 以typedef重新定义块类型,可令块变量用起来更加简单。
- 定义新类型时应遵从现有的命名习惯,勿使其名称与别的类型相冲突。
- 不妨为同一个块签名定义多个类型别名。如果要重构的代码使用了块类型的某个别名,那么只需要修改相应typedef中的块签名即可,无须改动其他typedef。
39.用handler块降低代码分散程度
协议传值实现异步
- 为用户界面编码时,一种常用的范式就是“异步执行任务”。这种范式的好处在于:处理用户界面的显示及触摸操作所用的线程,不会因为要执行I/O或网络通信这类耗时的任务而阻塞。这个线程通常称为主线程。
- 异步执行任务的通常使用委托模式实现,也就协议传值
块实现异步
- 将一个方法定义为块类型当作参数传给某个方法
- 委托模式还有缺点就是如果类分别使用多个获取器下载不同的数据,那么就得在delegate回调方法里根据传入参数切换
- 而使用块无需在回调方法里面切换,每个completion handler的逻辑都已经定义好了
回调操作里的块
有时需要在相关事件点执行回调操作,这种情况也可以使用handler块。就比如说是下载应用的进度条。我们为其添加一个观察者,并且在其值发生改变的时候我们调用其中的块。
要点
- 在创建对象时,可以使用内联的handler块将相关的业务逻辑一并声明。
- 在有多个实例需要监控时,如果采用委托模式,那么经常需要根据传入的对象来切换,而若改用handler块来实现,则可以直接将块与相关对象放在一起。
- 设计API时如果用到了handler块,那么可以增加一个参数,使用调用者可以通过此参数来决定应该把块安排在哪个队列上执行。
40.用块引用其所属对象时不要出现保留环
块中也存在保留环
- 如果块所捕获的对象直接或间接的保留了块本身,那么就会出现一种相互引用的现象吗,也就是块中的保留环
- 保留环主要还是互相引用,尤其是在块的回调部分出现,可能你意识不到的时候就存在了保留环。
- 只要合适的时候清除掉一方引用,就可以解决问题。
要点
总结
原文地址:https://blog.csdn.net/weixin_61639290/article/details/128790090
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_25542.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。