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代码块被保存在堆或者静态区中,不会被保存在栈中,如下图可以说明这一点。

示例
- (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时候可以不考虑这些,编译器会自动帮我们判断什么时候释放,什么时候保持。
// 用法示例:
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的经典。

	__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判空。

OC语言Block 续的更多相关文章

  1. OC语言BLOCK和协议

    OC语言BLOCK和协议 一.BOLCK (一)简介 BLOCK是什么?苹果推荐的类型,效率高,在运行中保存代码.用来封装和保存代码,有点像函数,BLOCK可以在任何时候执行. BOLCK和函数的相似 ...

  2. 李洪强iOS开发之OC语言BLOCK和协议

    OC语言BLOCK和协议 一.BOLCK (一)简介 BLOCK是什么? 苹果推荐的类型,效率高,在运行中保存代码.用来封装和保存代码,有点像函数,BLOCK可以在任何时候执行. BOLCK和函数的相 ...

  3. OC语言-block and delegate

    参考博客 OC语言BLOCK和协议 iOS Block iOS Block循环引用精讲 iOS之轻松上手block 深入浅出Block的方方面面 Block apple官方参考 1.定义一个block ...

  4. OC语言Block

    OC语言Block 一.Block (一)简介  Block是什么?苹果推荐的比较特殊的数据类型,效率高,在运行中保存代码.用来封装和保存代码,有点像函数,BLOCK可以在任何时候执行. Block和 ...

  5. iOS OC语言: Block底层实现原理

    先来简单介绍一下BlockBlock是什么?苹果推荐的类型,效率高,在运行中保存代码.用来封装和保存代码,有点像函数,Block可以在任何时候执行. Block和函数的相似性:(1)可以保存代码(2) ...

  6. iOS OC语言: Block底层实现原理 (转载)

    作者:Liwjing 地址:http://www.jianshu.com/users/8df89a9d8380/latest_articles 先来简单介绍一下Block Block是什么? 苹果推荐 ...

  7. oc语言--BLOCK和协议

    一.BOLCK (一)简介 BLOCK是什么?苹果推荐的类型,效率高,在运行中保存代码.用来封装和保存代码,有点像函数,BLOCK可以在任何时候执行. BOLCK和函数的相似性:(1)可以保存代码(2 ...

  8. Object-C语言Block的实现方式

    开场白 Block基本概念 中间态转换方法 Block编译后结果分析 Block运行时状态与编译状态对比   开场白   Object-C语言是对C语言的扩展,所以将OC源码进行编译的时候,会将OC源 ...

  9. 一.OC基础之:1,OC语言的前世今生 ,2,OC语言入门,3,OC语言与C的差异,4,面向对象,5,类和对象的抽象关系,6,类的代码创建,7,类的成员组成及访问

    1,OC语言的前世今生 , 一, 在20世纪80年代早期,布莱德.麦克(Brad Cox)设计了OC语言,它在C语言的基础上增加了一层,这意味着对C进行了扩展,从而创造出一门新的程序设计语言,支持对象 ...

随机推荐

  1. DRF的认证,频率,权限

    1,DRF的认证 初识认证:浏览器是无状态的,一次导致每次发的请求都是新的请求,所以每次请求,服务器都会进行校验,这样就很繁琐,这趟我们就需要给每一个用户登录后一个新的标识,浏览器每次都会带着这个唯一 ...

  2. 不同linux版本下内核/系统/软件的安装及查询

    (一)先介绍下使用apt-get 和使用yum 包管理工具的不同用法: 1.先看yum(redhat) yum的配置文件是/etc/yum.conf 更新:yum update 安装:yum inst ...

  3. svn问题:在eclipse里面使用SVN,怎么实现版本回滚呢?

    共有4个答案 我要回答» JustForFly 回答于 2012-04-27 10:20 举报   想回到SVN服务器端的最新版本就使用 team->还原.. 想回到SVN服务器端的其它版本使用 ...

  4. Outlook 2007 发送邮件

    4 登入以投票 Hi, http://social.msdn.microsoft.com/Forums/zh-TW/6c063b27-7e8a-4963-ad5f-ce7e5ffb2c64/how-t ...

  5. 80个Python经典资料(教程+源码+工具)汇总——下载目录 ...

    原文转自:http://bbs.51cto.com/thread-935214-1.html 大家好,51CTO下载中心根据资料的热度和好评度收集了80个Python资料,分享给Python开发的同学 ...

  6. 解决Linux主机上的 远程MySQL客户端无法连接的问题

    无法连接到 MySQL 数据库可能的原因有: 1. PHP 无法连接 MySQL 可能是 PHP 配置不正确,没加上连接 MySQL 的功能. 2. MySQL 软件包升级,但没有升级数据库,或安装 ...

  7. ChartCtrl源码剖析之——CChartGrid类

    CChartGrid类用来绘制波形区域中的表格,当绘制波形时波形就显示在这些表格上面.它处于该控件的区域,如下图所示: CChartGrid类的头文件. #if !defined(AFX_CHARTG ...

  8. linux简单技巧和怎么样进入root用户

    1.使用shell的Tab键自动补全 Tab在linux命令行输入中可以自动完成.在linux 命令行中使用Tab键会极大提高输入效率2.使用shell的历史记录 shell会记录用户执行命令的历史记 ...

  9. unity3d中对像之间的相互作用的实现

    首先这里的对像是面向对像中的对像: 其实就是C#中对像间相互作用的实现: 一.一般面向对像中关联和依赖的方式: 如关联方式: class A{ B m_B; A(B b){ m_B = b; } ac ...

  10. P3171 [CQOI2015]网络吞吐量

    传送门 首先跑一遍最短路,如果一条边满足\(dis[v]=dis[u]+w[i]\),那么这条边就在最短路中,把它加进网络流的图里 然后点的流量限制的话拆点,把每个点拆成两个,中间连边来限制流量 最后 ...