iOS块和强/弱引用自我

我有一个关于在iOS中对块自我强和弱引用的问题。 我知道在块内引用self的正确方法是在块外创build一个弱引用,然后在块内引用弱引用,如下所示:

__weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^ { typeof(self) strongSelf = weakSelf; NSLog(@"%@", strongSelf.someProperty); }); 

但是,如果你有嵌套块会发生什么? 这一套引用是否足够了? 或者你需要为每个块新的设置? 例如,以下哪一项是正确的?

这个:

 __weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^ { typeof(self) strongSelf = weakSelf; NSLog(@"%@", strongSelf.someProperty); dispatch_async(dispatch_get_main_queue(), ^ { strongSelf.view.frame = CGRectZero; }); }); 

或这个:

 __weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^ { typeof(self) strongSelf = weakSelf; NSLog(@"%@", strongSelf.someProperty); __weak typeof(strongSelf) weakSelf1 = strongSelf; dispatch_async(dispatch_get_main_queue(), ^ { typeof(strongSelf) strongSelf1 = weakSelf1; strongSelf1.view.frame = CGRectZero; }); }); 

任何信息或解释非常感谢!

你不需要做两套弱引用。 你想避免块是一个保留周期 – 两个对象保持对方不必要地活着。

如果我有这个属性的对象:

 @property (strong) void(^completionBlock)(void); 

我有这个方法:

 - (void)doSomething { self.completionBlock = ^{ [self cleanUp]; }; [self doLongRunningTask]; } 

当我将它存储在completionBlock属性中时,块将保持活动状态。 但是因为它在块内引用了self ,所以块会保持self活力直到它消失 – 但是这不会发生,因为它们都是相互引用的。

在这个方法中:

 - (void)doSomething { [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self cleanUp]; }]; [self doLongRunningTask]; } 

你不需要对自己做一个弱self 。 该块会保持self活力,因为它从内部引用self ,但是因为我们所做的只是将块移交给[NSOperationQueue mainQueue] ,所以self并没有保持块的活性。

希望这可以帮助。

这两个构造都很好。 这只取决于你的意图。 (a)在外部程序段开始后释放,但是(b)在主要程序段内部程序段开始之前,你想要发生什么? 如果你不希望它保留在这个场景中(我猜可能是你的意图,因为你首先经历了这个weakSelf练习),然后用你最后的例子,你有第二个弱指针。 否则,你可以使用你的另一个例子。

话虽如此,一些观察:

  1. 首先,你不得不使用这种weakSelf模式。 有些人误认为他们不得不用这种weakSelf模式来避免一个强有力的参照周期(aka保留周期)。 但是这个代码示例并不构成强大的参考周期。 它只是在调度代码执行时保留对象,这是一个非常不同的考虑因素。

    事实上,有时你需要/想要的。 有时候你没有。 这取决于您正在解决的业务问题。 当然,你经常不想让自己保持一个强有力的参考,在这种情况下, weakSelf模式非常有意义。 但情况并非总是如此。

    但是我的观点是,你不应该为了避免一个强大的参考周期weakSelf追求这个weakSelf模式(至less在这个dispatch_async场景中)。 没有这样的循环存在。 在哪里这是一个问题是你有一个块variables(例如一些completionHandler块)。 在这种情况下, weakSelf模式是至关重要的。 但不在这里。

  2. 但是让我们考虑一下你不想self保留的情景。 那么,是否要让代码继续运行呢? 如果没有,也许你应该使用可取消操作的操作队列而不是GCD。

    例如,我惊讶地发现,在一些后台networking请求正在运行的时候,他们是否要保留视图控制器,但是不用担心他们是否应该首先取消后台networking请求。 通常,后者是一个更重要的devise考虑因素(例如,您下载的PDF或图像比视图控制器所需的系统资源(内存和networking带宽)都要多得多)。

  3. 但是,假设(a)你确实希望分派的代码继续执行,但是(b)你不想保留self 。 (这似乎是一种罕见的情况,但是这是你所问过的,所以让我们来追求这一点。)最后一个问题是,你是否需要你的strongSelf构造。 在你的情况下,你只要调用单一的self方法,你就不需要打扰这个strongSelf构造。 只有当你要尊重个人或者需要避免竞争的情况下,这才是关键。 但是,在这个例子中,考虑到发送给一个nil对象的消息什么也不做,你在技术上往往不需要担心这个strongSelf构造。

不要误解我的意思 在weakSelf模式下,以及有时伴随而来的嵌套strongSelf模式是很好的。 我只是build议理解何时这些模式是真正需要的。 我认为,GCD与可取消的NSOperation的select通常是一个更为关键的问题,但往往被忽视。

块被创build并存储在堆栈上。 所以当创build块的方法返回时,块将被销毁。

如果一个块成为一个实例variables,则ARC将该块从堆栈复制到堆中。 您可以显式复制带有复制消息的块。 你的块现在是一个基于堆的块,而不是一个基于堆栈的块。 你必须处理一些内存pipe理问题。 块本身将保持强引用它引用的任何对象。 在块外部声明__weak指针,然后在块内引用该指针以避免保留周期。