Block使用中的一些疑问解答

本文详细介绍了Objective-C中Block的基本使用方法,包括如何在Block中引用外部变量、Block自身的内存管理策略,以及如何避免Block引起的循环引用导致的内存泄露问题。通过实例演示了在不同场景下Block的正确使用方式,提供了防止内存泄露的有效解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文由泰然教程组 jesse 原创,版权所有,转载请注明原出处,并通知原作者!!!

原文地址:http://jessex.me/?p=181

本文主要是阐述一下Block中如何的使用外部变量以及block本身的内存管理。

先定义一个block变量,作为后续的例子中使用:

  1. typedefvoid(^BlockCC)(void);
  2. BlockCC _block;


 

1、block中引用外部变量

block中可以直接使用外部的变量,比如

 

  1. int number =1;
  2. _block =^(){
  3. NSLog(@"number %d", number);
  4. };


那么实际上,在block生成的时候,是会把number当做是常量变量编码到block当中。可以看到,以下的代码,block中的number值是不会发生变化的:

 

  1. int number =1;
  2. _block =^(){
  3. NSLog(@"number %d", number);
  4. };
  5. number =2;
  6. _block();


则输出的值为 1,而不是2。原因就是如上所说。

如果要在block中尝试改变外部变量的值,则会报错的。对于这个问题的解决办法是引入__block标识符。将需要在block内部修改的变量标识为__block scope。更改后的代码如下:

 

  1. __block int number =1;
  2. _block =^(){
  3. number++;
  4. NSLog(@"number %d", number);
  5. };


而这个时候,其实block外部的number和block内部的number指向了同一个值,回到刚才的在外部改变block的例子,它的输出结果将是2,而不是1。有兴趣的可以自己写一个例子试试。

 

 

2、block自身的内存管理

block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈(stack)上,而不是在堆(heap)上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。比如下面的例子。
我在view did load中创建了一个block:

 

  1. -(void)viewDidLoad
  2. {
  3. [superviewDidLoad];
  4.  
  5. int number =1;
  6. _block =^(){
  7.  
  8. NSLog(@"number %d", number);
  9. };
  10. }

并且在一个按钮的事件中调用了这个block:

 

 

  1. -(IBAction)testDidClick:(id)sender {
  2. _block();
  3. }

此时我按了按钮之后就会导致程序崩溃,解决这个问题的方法就是在创建完block的时候需要调用copy的方法。copy会把block从栈上移动到堆上,那么就可以在其他地方使用这个block了~
修改代码如下:

 

  1. _block =^(){
  2. NSLog(@"number %d", number);
  3. };
  4.  
  5. _block =[_blockcopy];


同理,特别需要注意的地方就是在把block放到集合类当中去的时候,如果直接把生成的block放入到集合类中,是无法在其他地方使用block,必须要对block进行copy。不过代码看上去相对奇怪一些:

  1. [array addObject:[[^{
  2. NSLog(@"hello!");
  3. } copy] autorelease]];

 

3、循环引用

这一点其实是在第一点的一个小的衍生。当在block内部使用成员变量的时候,比如

 

  1. @interfaceViewController:UIViewController
  2. {
  3. NSString*_string;
  4. }
  5. @end


在block创建中:

  1. _block =^(){
  2. NSLog(@"string %@", _string);
  3. };


这里的_string相当于是self->_string;那么block是会对内部的对象进行一次retain。也就是说,self会被retain一次。当self释放的时候,需要block释放后才会对self进行释放,但是block的释放又需要等self的dealloc中才会释放。如此一来变形成了循环引用,导致内存泄露。
修改方案是新建一个__block scope的局部变量,并把self赋值给它,而在block内部则使用这个局部变量来进行取值。因为__block标记的变量是不会被自动retain的。

 

  1. __block ViewController*controller =self;
  2. _block =^(){
  3. NSLog(@"string %@", controller->_string);
  4. };

先写到这里,基本是我在用block时候碰到的一些问题。需要更详细的解释,可以看看《Adanced Mac OS X Programming》这本书,推荐给大家。

转载于:https://www.cnblogs.com/pengyingh/articles/2514353.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值