Block使用中的一些要注意的地方
本文主要是阐述一下Block中如何的使用外部变量以及block本身的内存管理。
先定义一个block变量,作为后续的例子中使用:
typedef void(^BlockCC)(void);
BlockCC _block;
1、block中引用外部变量
block中可以直接使用外部的变量,比如
int number = 1;
_block = ^(){
NSLog(@"number %d", number);
};
那么实际上,在block生成的时候,是会把number当做是常量变量编码到block当中。可以看到,以下的代码,block中的number值是不会发生变化的:
int number = 1;
_block = ^(){
NSLog(@"number %d", number);
};
number = 2;
_block();
则输出的值为 1,而不是2。原因就是如上所说。
如果要在block中尝试改变外部变量的值,则会报错的。对于这个问题的解决办法是引入__block标识符。将需要在block内部修改的变量标识为__block scope。更改后的代码如下:
__block int number = 1;
_block = ^(){
number++;
NSLog(@"number %d", number);
};
而这个时候,其实block外部的number和block内部的number指向了同一个值,回到刚才的在外部改变block的例子,它的输出结果将是2,而不是1。有兴趣的可以自己写一个例子试试。
2、block自身的内存管理
block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈(stack)上,而不是在堆(heap)上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。比如下面的例子。
我在view did load中创建了一个block:
- (void)viewDidLoad
{
[superviewDidLoad]; int number = 1;
_block = ^(){ NSLog(@"number %d", number);
};
}
并且在一个按钮的事件中调用了这个block:
- (IBAction)testDidClick:(id)sender {
_block();
}
此时我按了按钮之后就会导致程序崩溃,解决这个问题的方法就是在创建完block的时候需要调用copy的方法。copy会把block从栈上移动到堆上,那么就可以在其他地方使用这个block了~
修改代码如下:
_block = ^(){
NSLog(@"number %d", number);
}; _block = [_blockcopy];
同理,特别需要注意的地方就是在把block放到集合类当中去的时候,如果直接把生成的block放入到集合类中,是无法在其他地方使用block,必须要对block进行copy。不过代码看上去相对奇怪一些:
[array addObject:[[^{
NSLog(@"hello!");
} copy] autorelease]];
3、循环引用
这一点其实是在第一点的一个小的衍生。当在block内部使用成员变量的时候,比如
@interface ViewController : UIViewController
{
NSString *_string;
}
@end
在block创建中:
_block = ^(){
NSLog(@"string %@", _string);
};
这里的_string相当于是self->_string;那么block是会对内部的对象进行一次retain。也就是说,self会被retain一次。当self释放的时候,需要block释放后才会对self进行释放,但是block的释放又需要等self的dealloc中才会释放。如此一来变形成了循环引用,导致内存泄露。
修改方案是新建一个__block scope的局部变量,并把self赋值给它,而在block内部则使用这个局部变量来进行取值。因为__block标记的变量是不会被自动retain的。
__block ViewController *controller = self;
_block = ^(){
NSLog(@"string %@", controller->_string);
};
先写到这里,基本是我在用block时候碰到的一些问题。需要更详细的解释,可以看看《Adanced Mac OS X Programming》这本书,推荐给大家
Block使用中的一些要注意的地方的更多相关文章
- IOS block使用中碰到的一个小坑
1.先上段代码 __block typeof(self) tmpSelf = self; [tableview addLegendHeaderWithRefreshingBlock:^() ...
- Block编程值得注意的那些事儿
[深入浅出Cocoa]Block编程值得注意的那些事儿 [深入浅出Cocoa]Block编程值得注意的那些事儿 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循 ...
- Block编程注意的问题
一,前言 block 是在 iOS 4 中引入的新特性,它和 C++ 11 中的 lamba 表达式概念相似,有时候也被称为闭包.经过一段时间的使用,我发现要用对用好 block 还是有不少需要注 ...
- Objective-C中block的底层原理
先出2个考题: 1. 上面打印的是几,captureNum2 出去作用域后是否被销毁?为什么? 同样类型的题目: 问:打印的数字为多少? 有人会回答:mutArray是captureObject方法的 ...
- block的语法
主要内容: 1. 开始使用block(Getting Started with Blocks) 2. block概念综述(Conceptual Overview) 3. 声明和创建block(Decl ...
- 深入理解block
2010年WWDC发布iOS4时Apple对Objective-C进行了一次重要的升级:支持Block.说到底这东西就是闭包,其他高级语音例如Java和C++已有支持,第一次使用Block感觉满简单好 ...
- Block的引用循环问题 (ARC & non-ARC)
2010年WWDC发布iOS4时Apple对Objective-C进行了一次重要的升级:支持Block.说到底这东西就是闭包,其他高级语音例如Java和C++已有支持,第一次使用Block感觉满简单好 ...
- iOS block的用法
本章学习目标: 1. 了解何谓block. 2. 了解block的使用方法. Block 是iOS在4.0之后新增的程式语法,严格来说block的概念并不算是基础程式设计的范围,对初学者来说也不是很容 ...
- block 浅析
最近讲了一个关于block的例子 block 可以作为一个参数 进行传递 需要注意的地方是 :block 虽然作为一个参数 但是在函数方法执行的时候 block 是不会在定义它的地方调用 除非你在后边 ...
随机推荐
- PHP微信支付开发之扫描支付(模式二)后如何回调
其实在写这篇文章的时候感觉自己已经落伍了,不过笔者在百度上搜索"微信支付开发之扫描支付(模式二)后如何回调"寻找答案时,发现依旧有很多朋友没有解决这个问题,所以就把自己的解决思路分 ...
- #数论-模运算#POJ 1150、1284、2115
1.POJ 1150 The Last Non-zero Digit #质因数分解+模运算分治# 先贴两份题解: http://www.hankcs.com/program/algorithm/poj ...
- HDOJ-1052 田忌赛马(贪心)
田忌赛马 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述: Here is a famous story in Chinese history. "That was ...
- c#代码发送post请求,上传文件(并带其他参数)
本人对post理解不深,前段时间遇到一个需要用c#代码发送post请求上传文件的业务,于是参考了几篇帖子,加上自身实践写出了如下代码.写的比较low 望各位大大指正^_^. 业务需求: 对方给了一个接 ...
- oracle数据库 参数open_cursors和session_cached_cursor详解!
open_cursors 每个session(会话)最多能同时打开多少个cursor(游标) session_cached_cursor 每个session(会话)最多可以缓存多少个关闭掉的curso ...
- mac版Tomcat安装
挺好安装的,就是网上资料有的错了. 1.下载Tomcat 网址:http://tomcat.apache.org,解压在~/Downloads 目录下,我的版本是apache-tomcat-7.0.7 ...
- java 枚举类型和数据二进制等问题思考
.以下代码的输出结果是什么? int X=100; int Y=200; System.out.println("X+Y="+X+Y); System.out.println(X+ ...
- js中三目运算符和&& || 符的个人浅见
这两天看到别人写的代码,感觉很牛逼,如下,大神请忽视 $(".lgn").on("click", function() { var a = {}; a.logi ...
- KVM下windows虚拟机使用virtio驱动
KVM下windows虚拟机默认disk使用的是Qemu IDE硬盘,网卡默认是rtl8139网卡.为了使kvm主机在相同的配置下,有更好的效率,可以将网卡和磁盘替换成virtio的驱动. windo ...
- Gdiplus 贴图(助记) -------------------拖动整个对话框
最简单的两种方法: 一.使WM_NCHITTEST始终返回HTCAPTION,也就是欺骗系统让他以为这是菜单栏. LRESULT CDemoDlg::OnNcHitTest(CPoint point) ...