1.首先来看典型的block循环引用
#import "ViewController.h" @interface ViewController () @property (copy,nonatomic) void (^printBlock)(); @property (copy,nonatomic) NSString *name; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.name=@"wall"; self.printBlock=^(){ NSLog(@"%@",self.name); }; self.printBlock(); // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
分析:这是典型的循环引用,如下图所示:self强引用printBlock,而printBlock也强引用self
2.解决办法
#import "ViewController.h" @interface ViewController () @property (copy,nonatomic) void (^printBlock)(); @property (copy,nonatomic) NSString *name; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.name=@"wall"; __weak typeof(self)weakSelf=self; self.printBlock=^(){ typeof(weakSelf)strongSelf=weakSelf; //使用弱引用的外部变量weakSelf NSLog(@"%@",strongSelf.name); }; self.printBlock(); // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
分析:由于weakSelf是弱引用指针,即代码块使用的是弱引用外部变量,所以printBlock弱引用self,用虚线箭头表示,self任然强引用printBlock,此时并没有形成循环引用。还有非常重要的一点需要注意,就是为什么代码块内打印name值的时候,使用的是strongSelf?这是因为,如果使用weakSelf,当ViewController对象被释放的时候,weakSelf=nil,再使用weakSelf是无效的,而使用strongSelf就可以解决这个问题。但是有人可能会问,这样的话,不是又循环引用了吗?尤其是看下面这张图。其实这样并不是循环引用,因为strongSelf是在代码块内部定义的,属于代码块局部变量,代码块使用完后就会被释放,所以就不存在所谓的循环引用。
(1)如果【block内部】使用【外部声明的强引用】访问【对象A】, 那么【block内部】会自动产生一个【强引用】指向【对象A】
(2)如果【block内部】使用【外部声明的弱引用】访问【对象A】, 那么【block内部】会自动产生一个【弱引用】指向【对象A】