//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
我再次保留weakSelf
,NSTimer
会保留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");
});
});
它看起来很矛盾。
答案 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)
)发送到weakSelf
,self
将timer
保留为实例变量,保留循环。
让我们来看看这个块,默认情况下,当块从堆栈移动到堆时,块会保留任何NSObject
它捕获。
_block
(在您的情况下)是一个实例变量,当它被分配一个块时,该块将发送一个复制方法,因此它将从堆栈移动到堆。
但如果抓取的object
包含__weak
或__unsafe_unretained
属性,则不会向其发送保留方法。规则由编译器定义,因此它可以工作。
如果您想了解详细信息,请查看源代码runtime.c,您可能还需要汇总代码,因为runtime.c
没有ARC代码。
如果您对这行代码__strong Parent *parent=weakSelf
感到困惑,请检查this answer。