为什么我需要为某些完成块而不是其他块创建一个线程安全版本的你自己?

Why do I need to create a threadsafe version of self for some completion blocks and not others?

我有一个带有 UIPageViewController 的视图和设置视图控制器的方法我使用了一个线程安全的 self 实例,如下所示:

__block typeof(self) threadedSelf = self;

[self.pageController setViewControllers:@[p]
                              direction:UIPageViewControllerNavigationDirectionReverse
                               animated:YES
                             completion:^(BOOL finished){
                                 if (finished) {
                                     [threadedSelf performSelectorOnMainThread:@selector(setNavTitleText) withObject:nil waitUntilDone:NO];
                                 }
                             }];

完成块看起来与其他完成块相似,例如 UIView 动画方法,但这是我必须创建块版本的第一个完成块。为什么此方法与其他完成回调不同?是不是因为这是UIView动画是class(静态)方法的实例方法?

如果self 保留了一个引用self 的块,我们就有了一个循环保留。您试图避免的警告是告诉您这可能会发生在这里。我不知道这是不是真的,但是鉴于明确的警告,我没有机会:我将 self 的弱版本传递到块中,使用 "weak-strong dance".

这实际上不是线程安全问题,而是保留周期问题。块保留它们使用的对象。显然,从警告来看,这个块被self保留,所以如果它uses/retainsself那么你有一个保留周期。

您应该在块中使用的指向自身的指针上使用 __weak 限定符,例如:

__weak typeof(self) weakSelf = self;

__weak__block都经常用于将出现在块中的变量,但它们有不同的用途。 __weak 限定符可防止块保留对象,这正是防止循环保留所需的工具。 __block 限定符确实阻止块保留对象,但它的目的实际上是指示对象可能在块内更改(即对块内对象所做的更改必须在块外可见) .在您的示例中,不是这种情况。您指的是 self 但您没有修改指针 (self = foo)。因此,您应该使用 __weak 限定符而不是 __block 限定符。

在许多情况下,您不需要限定词。只有当块实际上被块内引用的对象保留时,才会有一个保留周期。您经常会使用您拥有的任何对象都没有保留的块,例如:

[UIView animateWithDuration:0.2 animations:^{
    [self makeSomeChangesToBeAnimated];
}];

此处动画块可以安全地引用 self 而无需限定符,因为该块未被 self 保留。它可能会被 else 保留,但不会被 self 保留,因此您不需要使用 __weak 限定符。