iOS内存话题: 实例变量造成的循环引用

来源:互联网 发布:js验证用户名 编辑:程序博客网 时间:2024/04/28 23:06

OC 中关于成员变量和属性的区别, 在阅读下面内容之前请自行 google.

工程目录如下


示例较简单, ViewController 直接打开 CoreViewController.

完整例子下载, 请戳这里!


Person.h

#import <Foundation/Foundation.h>typedef void(^PlayFunction)(int x);@interface Person : NSObject@property (strong, nonatomic) PlayFunction playBlock;@end

Person.m 

没有任何实现.


ViewController.m

#import "ViewController.h"#import "CoreViewController.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];        CoreViewController *page = [CoreViewController new];    [self.navigationController pushViewController:page animated:YES];}@end


CoreViewController.m

#import "CoreViewController.h"#import "Person.h"@interface CoreViewController (){    BOOL isKill;}@property (strong, nonatomic) Person *person;@end@implementation CoreViewController- (void)dealloc{    NSLog(@"CoreViewController dealloc");}- (void)viewDidLoad{    [super viewDidLoad];        self.view.backgroundColor = [UIColor grayColor];        _person = [[Person alloc] init];    _person.playBlock = ^ void (int x) {        isKill = NO;    };}@end

编译运行, 在 CoreViewController 返回的时候, 我们发现其 dealloc 方法并没有被调用.

接下来, 我们注释掉 playBlock 里面的这句

 isKill = NO;

再编译运行, 发现 dealloc 方法被调用了.

也就是说, 原因在于 isKill 这个实例变量上面.


Person 是 CoreViewController 的强引用, 而 Person 的 block 属性对 CoreViewController也是强引用.

那么, 大家会说了, 修改 Person.h

#import <Foundation/Foundation.h>typedef void(^PlayFunction)(int x);@interface Person : NSObject@property (copy, nonatomic) PlayFunction playBlock;@end

发现还是不行.将 copy 改为 weak 吧, 没错, 这样的确可以.

但是, 你会看到编译器不高兴了.




看来这样不妥.

可能你会说, 在 ViewController 中将 person 改为 weak,

@property (weak, nonatomic) Person *person;

的确可以这么解决不释放的问题, 但是也有警告



那我们再换一种方式, 

- (void)viewDidLoad{    [super viewDidLoad];        self.view.backgroundColor = [UIColor grayColor];        _person = [[Person alloc] init];        CoreViewController __weak *weakSelf = self;    _person.playBlock = ^ void (int x) {        CoreViewController __strong *strongSelf = weakSelf;        strongSelf->isKill = NO;    };}

完美解决.

这里啰嗦一下, 千万不要使用 weakSelf 访问实例变量, 否则编译报错.



推荐阅读:

到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf

正确使用Block避免Cycle Retain和Crash


1 0