Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >OC语言Block 续

OC语言Block 续

作者头像
用户1941540
发布于 2018-05-11 05:22:56
发布于 2018-05-11 05:22:56
57700
代码可运行
举报
文章被收录于专栏:ShaoYLShaoYL
运行总次数:0
代码可运行

OC语言 Block

转载:http://blog.csdn.net/weidfyr/article/details/48138167

1.Block对象中的变量行为

结论:

  1. 在block代码块内部可以访问定义的全局变量,局部变量,静态局部变量,但是访问局部静态变量时候是只读的并且局部变量和在代码块中访问到的不是同一个地址的变量,他们在数值上相等,互相似乎没什么联系。 因为代码块中使用到局部变量的时候,会将局部变量进行const类型的copy,所以在代码块中访问到的局部变量都是只读的;静态变量和全局变量都存放在静态区,在程序运行过程中都存在,他们可以在不同的代码块中共享,不同代码块中访问到的同一个全局变量,局部变量是同一块内存的数据;对于普通局部变量在代码块中只读,全局变量和静态局部变量在代码块中可以读写。
  2. 在块句法的主体中,除块句法内部的局部变量和形参之外,还包含块句法当前位置处可以访问的变量;这些变量中包含外部变量也包含块中可以访问的局部变量。
  3. 代码块中访问局部变量时候,局部变量会从栈内存被const类型的copy一份到堆内存中。
块对象和函数指针的定义使用功能都差不多,块对象的精髓之处就在于,在块对象中可以访问到上下文的变量,而函数指针不能。
2.块对象的实例和生命周期
  • 1)块句法也可以写在函数的外部,当写在函数外面时候,只是在静态数据区分配一块内存给块对象,这块区域在程序执行期间会一直存在。
  • 2)块句法写在函数内部的时候,块对象和变量的生命周期和普通局部变量一样,块对象的内存区域会在执行包含块对象的函数时保存在栈上;该块对象的生命周期就是函数运行期间。
  • 3)在现实的实现中,当函数内的块语法不包含自动变量的时候,就没必要进行复制值,所以块对象的内存区域也会被保存在静态数据区。
  • 4)block代码块被保存在堆或者静态区中,不会被保存在栈中,如下图可以说明这一点。
示例
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)function
{
    int i;
    int (^blocks[10])(); //定义一个块对象类型的数组
    for (i = 0; i < 10; i++) { //for循环给数组赋值
        blocks[i] = ^{ return i; };
    }
    for (i = 0; i < 10; i++) { //打印数组中的内容,就是每个数组存放的代码块的返回值
        NSLog(@"%d", blocks[i]());
    }
}
// 如上代码,在非ARC环境下运行结果是10个9,原因是虽然循环了十次,但是只有一个实体。
// 以上代码在ARC环境下是正确的,后面做说明。
3.块对象的复制
  • 函数内的块对象和局部变量的生命周期相同,都只是在函数的执行期间。但是在函数的方法调用参数中直接代入块对象也是块对象的一种非常常见的用法,这时候使用与函数调用关系或栈状态无关的块对象是非常必要的。
  • 有一个函数可以复制块对象到新的堆内存,通过使用该函数,即使是在函数内部定义的块对象也能独立于栈被持续的使用,此外还有一个函数可以释放不需要的块对象。

Block_copy( block )

  • 1.参数为栈上的块对象的时候,返回堆上的块对象。参数为堆上的块对象或者静态区的块对象,不进行复制,直接返回原对象,但是会增加参数块对象的引用计数。

Block_release( block )

  • 2.减少参数块对象的引用计数。当引用计数减到0时候,块对象被释放。
  • 3.在使用这些函数的时候,需要引入头文件Block.h .堆上的块对象使用引用计数的方式来管理。即使使用垃圾回收也必须成对出现。使用ARC时候可以不考虑这些,编译器会自动帮我们判断什么时候释放,什么时候保持。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 用法示例:
g = Block_copy(block);
Block_rlease(g);
4.指定特殊变量 __block
  • ARC下测试结果和总结:
  • 非ARC下测试结果和总结:

使用block时候注意事项:

使用注意事项:

  • 1)在块内改变外部变量的值时候,在外部变量前加__block,否则该值在block块内部是只读的。
  • 2)在引用某个实例变量或者所在控制器本身时候,在ARC下,要再前面加__weak如:__weak (typeof(self) weak self = self), 在mrc下用__block, 这样做是为了避免内存泄露和循环引用。
  • 3)在使用block前需要对block指针做判空处理,如果是MRC的编译环境下,要先release掉block对象。
  • 4)在MRC的编译环境下,block如果作为成员参数要copy一下将栈上的block拷贝到堆上(因为block默认是在栈上创建的,如果在定义block的作用于外部使用block那么需要使用copy将block放到堆上)//MRC下:_sucBlock = [callbackBlock copy]; 不copy block会在栈上被回收。
  • 5)将block赋值为空,是解掉循环引用的重要方法。
  • 6)还有一种改法,在block接口设计时,将可能需要的变量作为形参传到block中,从设计上解决循环引用的问题。
  • 7)在多线程环境下(block中的weakSelf有可能被析构的情况下),需要先将self转为strong指针,避免在运行到某个关键步骤时self对象被析构。 第四、第五条合起来有个名词叫weak–strong dance,来自于2011 WWDC Session #322 (Objective-C Advancements in Depth)
  • 以下代码来自AFNetworking,堪称使用weak–strong dance的经典。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    __weak __typeof(self)weakSelf = self;
    AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {  
        __strong __typeof(weakSelf)strongSelf = weakSelf;  
        strongSelf.networkReachabilityStatus = status;  
        if (strongSelf.networkReachabilityStatusBlock) {  
            strongSelf.networkReachabilityStatusBlock(status);  
        }
    };
  • Review一下上面这段代码,里面玄机不少。
    • 第一行:__weak __typeof(self)weakSelf = self;
    • 如之前第四条所说,为防止callback内部对self强引用,weak一下。
    • 其中用到了__typeof(self),这里涉及几个知识点:
  • a. __typeof、typeof、typeof的区别
    • 恩~~他们没有区别,但是这牵扯一段往事,在早期C语言中没有typeof这个关键字,__typeof、__typeof__是在C语言的扩展关键字的时候出现的。
    • typeof是现代GNU C++的关键字,从Objective-C的根源说,他其实来自于C语言,所以AFNetworking使用了继承自C的关键字。
  • b.对于老的LLVM编译器上面这句话会编译报错,所以在很早的ARC使用者中流行__typeof(&*self)这种写法,
    • 原因如下大致说法是老LLVM编译器会将__typeof转义为 XXX类名 *const __strong的__strong和前面的__weak关键字对指针的修饰又冲突了,所以加上&*对指针的修饰。
    • 第三行:__strong __typeof(weakSelf)strongSelf = weakSelf; 按照之前第五条的说法给转回strong了,这里__typeof()里面写的是weakSelf,里面写self也没有问题,因为typeof是编译时确定变量类型,所以这里写self 不会被循环引用。
    • 第四、五、六行,如果不转成strongSelf而使用weakSelf,后面几句话中,有可能在第四句执行之后self的对象可能被析构掉,然后后面的StausBlock没有执行,导致逻辑错误。
    • 最后第五行,使用前对block判空。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-11-12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
iOS_理解Block(代码块)+底层实现
​ Block是对象,可以赋值,当参数,也可以放入Array和Dictionary中,可以retain和release。Block用“^”符号来表示,后面跟一对花括号,括号里是Block的实现代码。例如,下面就是一个简单的Block:
mikimo
2022/07/20
6280
iOS_理解Block(代码块)+底层实现
iOS_理解“属性”(property)这一概念
​ “属性”(property)是Objective-C的一项特性,用于封装对象中的数据。OC对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过“存取方法”(access method)来访问。其中“获取方法”(getter)用于读取变量值,而“设置方法”(setter)用于写入变量值。(这一概念已经定型,并且经由“属性”这一特性而成为Objective-C 2.0的一部分)开发者可以令编译器自动编写与属性相关的存取方法。也可以使用“点语法”(dot syntax)更为容易地依照类对象来访问存取其中的数据。下面介绍与属性相关的细节。
mikimo
2022/07/20
6480
iOS block探究(一): 基础详解你要知道的block都在这里
你要知道的block都在这里 转载请注明出处 https://cloud.tencent.com/developer/user/1605429 本文大纲 block基础语法 block基础使用 block常见问题 block进阶: 深入代码理解 block基础语法 block作为C语言的扩展,正在OC中发挥着举足轻重的作用,我们经常使用block块作为回调函数,这样做可以大大简化编程方式,多线程的核心也是block,因此,学会使用block并深入理解block有助于我们写出更好的代码。 block基础知识
WWWWDotPNG
2018/04/10
9290
3. __block  __weak  __strong   这都是做什么的
1.1 局部变量 局部自动变量,在Block中可被读取。Block定义时copy变量的值,在Block中作为常量使用,所以即使变量的值在Block外改变,也不影响他在Block中的值,Block此时对局部变量只是做了值传递的操作。 1.2 static 修饰的全局变量 因为全局变量或静态变量在内存中的地址是固定的,Block在读取该变量值的时候是直接从其所在内存地址读出,获取到的是最新值,而不是在定义时copy的常量。 1.3 对OC对象的截获 NSMutableArray *array = [NSMut
陈雨尘
2018/06/07
6170
再议Block
什么是Block? Block objects are a C-level syntactic and runtime feature. They are similar to standard C functions, but in addition to executable code they may also contain variable bindings to automatic (stack) or managed (heap) memory. A block can therefore m
rectinajh
2018/05/17
7280
iOS底层原理总结 - 探寻block的本质(二)
上一篇文章iOS底层原理总结 - 探寻block的本质(一)中已经介绍过block的底层本质实现以及了解了变量的捕获,本文继续探寻block的本质。 block对对象变量的捕获 block一般使用过程中都是对对象变量的捕获,那么对象变量的捕获同基本数据类型变量相同吗? 查看一下代码思考:当在block中访问的为对象类型时,对象什么时候会销毁? typedef void (^Block)(void); int main(int argc, const char * argv[]) { @autore
xx_Cc
2018/06/04
1K0
Block原理探究(下篇)-捕获变量分析及__block原理
主要内容: 1.分析Block捕获外部变量的过程 2.理解Block修改外部变量的限制 3.分析__block存储域类说明符的原理 4.理解__block变量的存储域 5.探究Block对对象的捕获过程 6.Block的循环引用问题
梧雨北辰
2019/10/08
1.7K0
Block原理探究(下篇)-捕获变量分析及__block原理
深入理解 weak-strong dance
这时handler持有 Block 对象,而 Block 对象虽然捕获了weakSelf,延长了weakSelf这个局部变量的生命周期,但weakSelf是附有__weak修饰符的变量,它并不会持有对象,一旦它指向的对象被废弃了,它将自动被赋值为nil。在多线程情况下,可能weakSelf指向的对象会在 Block 执行前被废弃,这在上例中无伤大雅,只会输出Self is nil,但在有些情况下(譬如在 Block 中有移除 KVO 的观察者的逻辑,在执行到该逻辑前 self 就释放了)就会导致 crash。这时可以在 Block 内部(第一句)再持有一次weakSelf指向的对象,保证在执行 Block 期间该对象不会被废弃,这就是所谓的 weak-strong dance:
Sheepy
2018/09/10
2.1K0
Block 详解
闭包 = 一个函数「或指向函数的指针」+ 该函数执行的外部的上下文变量「也就是自由变量」;Block 是 Objective-C 对于闭包的实现。
猿_人类
2019/08/20
1.1K0
iOS中Block的用法,举例,解析与底层原理(这可能是最详细的Block解析)
【摘要】这篇文章,首先在第1节中介绍Block的定义,以及与C里面函数的对比。然后,第2节介绍实际开发中经常会用到的Block语法形式,以供读者日后查阅。只知道怎么用却不知什么时候用?所以随后的第3节将介绍Block的应用场景。然而,用Block不当导致了Crash?所以,第4节有必要了解Block捕获变量的特性,以及循环引用的解决。另外,千万不要懒,一碰到Block就weak,要区分哪些不会引起循环引用。然而,如果对Block的内存机制不熟悉,也会导致Crash,所以第5节会介绍Block的内存机制。学到这里已经够用了。然而,你却想进一步了解Block的实现机制?第6节将简单介绍下clang的编译与Block的实现及其原理。
陈满iOS
2018/09/10
1.9K0
iOS中Block的用法,举例,解析与底层原理(这可能是最详细的Block解析)
关于Block
(1).block种类 全局块(NSGlobalBlock):存在于全局内存中, 相当于单例. 栈块(NSStackBlock):存在于栈内存中, 超出其作用域则马上被销毁. 堆块(NSMallocBlock):在于堆内存中, 是带引用计数的对象, 需要自行管理其内存.
honey缘木鱼
2019/12/16
5140
关于Block
面试驱动技术 - Block看我就够了【干货】
Block 在 iOS 算比较常见常用且常考的了,现在面试中,要么没面试题,有面试题的,基本都会考到 block 的点。本文特别干!(但是初中级iOSer应该能有所收获~)
小蠢驴打代码
2019/03/15
7950
面试驱动技术 - Block看我就够了【干货】
iOS block的一些理解和注意点
block的定义:带有自动变量(局部变量)的匿名函数。 一.block作为参数使用时应该使用copy来修饰。 原因1:当用weak,assign修饰block属性时,block访问外部变量,此时block的类型就是栈(stack)block。保存在栈中的block,当block所在函数方法返回结束,该block就会被销毁。在其他方法内部调用该block,就会引发野指针错误EXC_BAD_ACCESS。 原因2.当使用copy,strong修饰block属性时,block访问外部变量,此时block的类型时堆
大壮
2018/06/19
1.3K0
iOS - 老生常谈内存管理(三):ARC 面世
ARC全称Automatic Reference Counting,自动引用计数内存管理,是苹果在 iOS 5、OS X Lion 引入的新的内存管理技术。ARC是一种编译器功能,它通过LLVM编译器和Runtime协作来进行自动管理内存。LLVM编译器会在编译时在合适的地方为 OC 对象插入retain、release和autorelease代码来自动管理对象的内存,省去了在MRC手动引用计数下手动插入这些代码的工作,减轻了开发者的工作量,让开发者可以专注于应用程序的代码、对象图以及对象间的关系上。   本文通过讲解MRC到ARC的转变、ARC规则以及使用注意,来帮助大家掌握iOS的内存管理。   下图是苹果官方文档给出的从MRC到ARC的转变。
师大小海腾
2020/04/24
2.3K0
iOS - 老生常谈内存管理(三):ARC 面世
16道面试官必问你必须会的iOS面试题
一个 UIViewController 中的所有 view 之间的关系其实可以看成一棵树,UIViewController 的 view 变量是这棵树的根节点,其它的 view 都是根节点的直接或间接子节点
会写bug的程序员
2020/05/29
2.8K0
16道面试官必问你必须会的iOS面试题
OC底层探索25-深入浅出BlockOC底层探索25-深入浅出Block
在2.2中出现了值拷贝,而且在block中也不允许使用修改捕获参数,想过要block内部修改就需要__block声明变量。
用户8893176
2021/08/09
5330
OC底层探索25-深入浅出BlockOC底层探索25-深入浅出Block
老司机出品——源码解析之从Block说开去
近来把《iOS与OS X多线程和内存管理》这本书又掏出来看了一遍,这本书前前后后加起来看了能有三四遍了,每次看都有新的理解。现在就把个人对Block的一些理解记录下来。
老司机Wicky
2018/08/22
4700
老司机出品——源码解析之从Block说开去
Block
通过clang -rewrite-objc WYTest.m命令编译该.m文件,发现该block被编译成这个形式:
conanma
2021/10/28
5950
iOS常见的内存问题——循环引用
小编在这段儿时间测试过程中发现了好多内存问题,其中较大部分都是由于循环引用造成的内存泄漏,这里小编就借此类问题来给大家分享一下循环引用引发的原因及常见解决方案。
用户5521279
2019/12/10
1.8K0
iOS常见的内存问题——循环引用
深入研究Block用weakSelf、strongSelf、@weakify、@strongify解决循环引用
在上篇中,仔细分析了一下Block的实现原理以及__block捕获外部变量的原理。然而实际使用Block过程中,还是会遇到一些问题,比如Retain Circle的问题。
一缕殇流化隐半边冰霜
2018/08/29
1.6K0
深入研究Block用weakSelf、strongSelf、@weakify、@strongify解决循环引用
相关推荐
iOS_理解Block(代码块)+底层实现
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验