关于__unsafe_unretained或_weak为什么可以解决保留周期

时间:2016-05-11 03:55:53

标签: objective-c retain-cycle

//Parent.m
#import "Parent.h"
@implementation Parent{
    dispatch_block_t  _block;
    NSTimer  *_timer;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self commonInitialization];
    }
    return self;
}

-(void)commonInitialization{
    __unsafe_unretained typeof(self) weakSelf=self;
    //__weak typeof(self) weakSelf=self; the same conculsion

    //apple doc:The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to this object until it (the timer) is invalidated.

    _timer=[NSTimer timerWithTimeInterval:0.5 target:weakSelf selector:@selector(sayHello) userInfo:nil repeats:YES];// make weakSelf retain count +1

    _block=^{
        __strong Parent *parent=weakSelf;//also make weakSelf retain count +1,but the actual is that this wont make self retain count +1

        [parent sayHello];//
    };

   // my question is why weakSelf can make _block wont retain self,but _timer will retain self,it look like contradictory
}

-(void)sayHello{
    NSLog(@"hello");
}

-(void)dealloc{
    NSLog(@"Parent instance can dealloc");
}

@end

_block我再次保留weakSelfNSTimer会保留target:weakSelf

我的问题是为什么__unsafe_unretained__weak可以使_block无法获得自我,但_timer不能。var robot = require("robotjs"); it('Testing robotjs', function () { browser.driver.get("www.abc.com"); element(by.xpath(button1)).click(); element(by.xpath(textArea)).click().then(function () { robot.typeString("hello world"); robot.moveMouse("605", "429"); robot.mouseClick("left"); }); }); 它看起来很矛盾。

3 个答案:

答案 0 :(得分:0)

当类实例具有对类的强引用时,保留具有块的循环,而块又具有对该实例的强引用。通过捕获块中的实例的弱引用(weakSelf),可以将捕获的引用设置为nil。在块中引用强引用仅意味着在块执行时,实例将不是dealloc&#d; dd(因为块仍然具有实时引用)

计时器在内部维护对实例的强引用,就像块在执行时一样。主要区别在于计时器是一个长期存在的对象,除非您使其无效或nil所有对它的引用,计时器仍然存在,以及它对您的实例的强引用。

答案 1 :(得分:0)

我真的不知道,我是否理解正确。你的意思是“保留”“保留”吗?

然而,两段代码之间的区别在于执行时间以及如何处理引用:

请记住,不保留对象引用,而是保留它们指向的对象。

一个。计时器

{
  __weak typeof(self) weakSelf=self;
  _timer=[NSTimer timerWithTimeInterval:0.5 target:weakSelf …];
}

使用此代码,您可以创建一个名为weakSelf的其他本地变量,它不会保留它指向的对象。此外,weakSelf的范围(“生命周期”)以C块结束(关闭所谓的__block),这意味着关闭{{1} }}。所以我们有:

}

在这种情况下,弱化{ __weak typeof(self) weakSelf=self; // does not retain self; no problem _timer=[NSTimer timerWithTimeInterval:0.5 target:weakSelf …]; // weakSelf dies, since it is weak nothing happens. }

是完全没有意义的
self

这始终是平衡的,因为ARC关心它。没问题。

那为什么会有保留周期?它是“在计时器内”。根据文件:

  

定时器触发时,aSelector指定的消息发送到的对象。计时器保持对该对象的强引用,直到它(计时器)无效为止。

因此,让我们回到你的例子:

{
  id anotherSelf=self;
  // does retain self: +1;

  _timer=[NSTimer timerWithTimeInterval:0.5 target:weakSelf …];

  // anotherSelf dies: -1
}

{ __weak typeof(self) weakSelf=self; // does not retain self; _timer=[NSTimer timerWithTimeInterval:0.5 target:weakSelf …]; // timer retains the object, weakSelf points to: +1. // self retains the timer: +1 // result: retain cycle // weakSelf dies, since it is weak nothing happens. } 的作用与-timerWithInterval…的强度无关。该方法甚至没有看到参考的强度。它保留了参数指向的对象。周期。

B中。块

有一个块是不同的:

weakSelf

如您所见,没有问题。为什么会有保留周期?这非常简单:在块内部有一个引用,当块创建时(类似于定时器)并且引用很强(与定时器不同)时保留引用的对象):

{
  __weak typeof(self) weakSelf=self;
  // does not retain self; no problem

_block=^{
    …
  };
  // weakSelf dies, since it is weak nothing happens.
}

只要块活着,这个参考就会存在。您必须正确阅读:它就像引用本身具有更长的生命周期。因此,它取决于参考的强度。

因此,无论您使用{ __weak typeof(self) weakSelf=self; // does not retain self; no problem _block=^{ … self … // the object self points to is retained, because self is strong. +1 … weakSelf … // the object weakSelf points to is not retained. … }; // weakSelf dies, since it is weak nothing happens. } 还是weakSelf(或任何其他弱或强引用),都会有很大差异。

块中完成了什么......:

self

...没有意义,因为这已经完成,当执行块时,本地_block=^{ __strong id strongSelf=weakSelf; }; 将立即失去其范围。 (再次结束strongSelf

答案 2 :(得分:0)

ARC和块都是编译器工作,编译器将添加retain release,它会将块转换为struct

NSTimer会强烈引用target,因此它会将保留方法(可能会在ARC中调用objc_retain(id value))发送到weakSelfselftimer保留为实例变量,保留循环。

让我们来看看这个块,默认情况下,当块从堆栈移动到堆时,块会保留任何NSObject它捕获

_block(在您的情况下)是一个实例变量,当它被分配一个块时,该块将发送一个复制方法,因此它将从堆栈移动到堆。

但如果抓取的object包含__weak__unsafe_unretained属性,则不会向其发送保留方法。规则由编译器定义,因此它可以工作。

如果您想了解详细信息,请查看源代码runtime.c,您可能还需要汇总代码,因为runtime.c没有ARC代码。

如果您对这行代码__strong Parent *parent=weakSelf感到困惑,请检查this answer