Block的陷阱总结

1、引发内存泄露
假设一个类有两个属性:block和name;

//
//  PHBlockTest.h
//  BlockTestTest
//
//  Created by 項普華 on 2017/2/9.
//  邮箱: xiangpuhua@126.com
//  电话: +86 13316987488
//  主页: https://github.com/xphaijj
//  Copyright © 2017年 項普華. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface PHBlockTest : NSObject

@property (nonatomic, copy) void(^block)();
@property (nonatomic, copy) NSString *name;

@end
//
//  PHBlockTest.m
//  BlockTestTest
//
//  Created by 項普華 on 2017/2/9.
//  邮箱: xiangpuhua@126.com
//  电话: +86 13316987488
//  主页: https://github.com/xphaijj
//  Copyright © 2017年 項普華. All rights reserved.
//

@implementation PHBlockTest
- (id)init
{
    if (self = [super init]) {
        self.block = ^{
            NSLog(@"%@",_name);
            NSLog(@"%@",self->_name);
            NSLog(@"%@",self.name);
        };
    }
    return self;
}
@end

普通情况下,block是存在于栈中的,意味着其生命周期由系统管理,不需要我们手动管理。这就存在一个问题,就是我们如果使用block保存一段代码块,在回调的时候,说不定已经被系统回收了。
因此我们需要想办法将block存储到堆中,方法就是使用copy,做一次复制。(如果使用retain的话,只会将其计数器加一,多做一次强引用,不会重新分类新的内存,所以依然存在于栈中)。 如上代码块中的m文件中的

NSLog(@"%@",_name);
NSLog(@"%@",self->_name);
NSLog(@"%@",self.name);

,此时如果在block中调用持有它的对象,就会产生循环引用,造成内存泄露。这个问题怎么引起的呢? 因为block存在于堆中,在其代码块中引用的对象都会产生一个强指针,而这个时候block本身就是被其引用的对象(copy)强指针指着。这样就造成了双方都无法释放,从而造成内存泄露。解决方案如下:

//
//  PHBlockTest.m
//  BlockTestTest
//
//  Created by 項普華 on 2017/2/9.
//  邮箱: xiangpuhua@126.com
//  电话: +86 13316987488
//  主页: https://github.com/xphaijj
//  Copyright © 2017年 項普華. All rights reserved.
//

@implementation PHBlockTest
- (id)init
{
    if (self = [super init]) {
        __unsafe_unretained PHBlockTest *temp = self;
        //__weak PHBlockTest *temp = self;
        self.block = ^{
            NSLog(@"%@", temp->_name);
            NSLog(@"%@", temp.name);
        };
    }
    return self;
}
@end

很多时候我使用的是下面的代码:

 __weak PHBlockTest *temp = self;

和上面的

__unsafe_unretained PHBlockTest *temp = self;

 有什么区别呢?

 简单说就是,unsafe,为什么不安全呢?因为当其所修饰的对象释放时,它并不知道,所以,其地址依然存在,不会清为nil,这样第七行代码

temp->_name
是可以访问的(在使用时也应当注意这个细节),而使用weak修饰的话,当其修饰的对象被释放时,temp会被清为nil,这样就会出现nil->_name的情况.这是不允许的.
如果想要了解
__unsafe_unretained和__weak的具体区别的话,可查阅其它资料.

为了防止上面所说的weak释放问题还有下面一种写法:

//
//  PHBlockTest.m
//  BlockTestTest
//
//  Created by 項普華 on 2017/2/9.
//  邮箱: xiangpuhua@126.com
//  电话: +86 13316987488
//  主页: https://github.com/xphaijj
//  Copyright © 2017年 項普華. All rights reserved.
//

@implementation PHBlockTest
- (id)init
{
    if (self = [super init]) {
        __weak PHBlockTest *temp = self;
        self.block = ^{
                    __strong PHBlockTest *strongSelf = temp;//防止在下面使用temp的时候  temp被释放掉
                    NSLog(@"%@", strongSelf->_name);
                    NSLog(@"%@", strongSelf.name);
        };
    }
    return self;
}
@end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值