3 回答
TA贡献1111条经验 获得超0个赞
这不仅有助于把重点放在strong或weak讨论的一部分。而是专注于循环部分。
保留周期是当对象A保留对象B 而对象B保留对象A 时发生的循环。在这种情况下,如果释放了任何一个对象,则:
因为对象B拥有对它的引用,所以不会释放对象A。
但是,只要对象A引用了对象B,就永远不会释放它。
但是对象A永远不会被释放,因为对象B拥有对它的引用。
广告无限
因此,即使在一切正常的情况下,这两个对象也应该在程序的生命周期内徘徊,即使它们在一切正常的情况下也应该被释放。
因此,我们担心的是保留周期,而创建这些周期的块本身没有任何问题。这不是问题,例如:
[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
[self doSomethingWithObject:obj];
}];
该块保留self,但self不保留该块。如果释放一个或另一个,则不会创建任何循环,并且一切都将按应有的方式释放。
您遇到麻烦的地方是这样的:
//In the interface:
@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);
//In the implementation:
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self doSomethingWithObj:obj];
}];
现在,您的对象(self)具有strong对该块的显式引用。并且该块具有对的隐式强引用self。这是一个周期,现在两个对象都不会被正确释放。
因为在这样的情况下,self 根据定义,已经有strong对该块的引用,所以通常最容易解决的方法self是为该块使用一个显式的弱引用:
__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[weakSelf doSomethingWithObj:obj];
}];
但这不应该是您在处理调用块时遵循的默认模式self!这仅应用于打破在self和block之间的保留循环。如果要在所有地方都采用这种模式,则冒着将块传递给在self释放后执行的操作的风险。
//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
//By the time this gets called, "weakSelf" might be nil because it's not retained!
[weakSelf doSomething];
}];
TA贡献1752条经验 获得超4个赞
您不必总是使用弱引用。如果您的块没有保留,而是被执行然后丢弃,则可以强烈地捕获自身,因为它不会创建保留周期。在某些情况下,您甚至希望该块保留自身,直到该块完成为止,这样它才不会过早地解除分配。但是,如果您强烈捕获该块,并在捕获自身内部,则会创建一个保留周期。
TA贡献1831条经验 获得超4个赞
但这不应该是您在处理称为self的块时遵循的默认模式!这仅应用于打破在self和block之间的保留循环。如果要在所有地方都采用这种模式,则冒着将块传递给在释放self之后执行的操作的风险。
//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
//By the time this gets called, "weakSelf" might be nil because it's not retained!
[weakSelf doSomething];
}];
为了克服这个问题,可以weakSelf在块内部定义一个强引用:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
MyObject *strongSelf = weakSelf;
[strongSelf doSomething];
}];
- 3 回答
- 0 关注
- 439 浏览
添加回答
举报