在块中使用局部变量名 "self" 是否正确?

Is it correct to use local variable name "self" in blocks?

我发现构造 __strong typeof(self)self = weakSelf.

它允许删除 NSAssert 宏 self 捕获,但我怀疑这样使用它是否正确?

__weak typeof(self)weakSelf = self;
self.signupBlock = ^{
    __strong typeof(self)self = weakSelf;
    NSLog (@"%d", self.property)
    NSAssert((self.property > 5), @"Some message");
}

请指教。

抱歉,我不得不先说使用 __strong typeof(self)strongSelf = weakSelf;

构造结果警告和我想内存循环,当NSAssert宏使用时,因为它包含self in.

self只是一个变量名,所以在本地重新定义它是完全可以的。它甚至可能比

更受欢迎
__strong typeof(weakSelf) strongSelf = weakSelf;

因为

  • 它使代码易于阅读
  • 它可以防止您错误地引用 "real" self 并可能创建保留循环。

此外,您可能想查看 this question for discussion when to use weak / strong self in blocks, and libextobjc 库的答案以获得简洁的 @weakify / @strongify 宏。

将代码更改为,以便清楚地表明您仅指块中的 strongSelf

__weak typeof(self) weakSelf = self;
self.signupBlock = ^{
    typeof(weakSelf) strongSelf = weakSelf;
    if strongSelf {
        NSLog (@"%d", strongSelf.property)
        NSAssert((strongSelf.property > 5), @"Some message");
    }
}

您的代码设置了与自身的弱连接 __weak typeof(self) weakSelf = self;。然后当它稍后需要调用 self 时,它会建立一个与 self typeof(weakSelf) strongSelf = weakSelf; 的强连接并检查 self 是否还在(尚未释放)if strongSelf {。如果是这样,强连接将使它保持活动状态,而其余代码是 运行,这在许多情况下可能涉及另一个块来调用主线程(即强连接)。

是的,在 ObjC 中使用 self 作为变量名是可以的。

我为需要打破由存储块引起的保留循环的情况制作了一个奇特的宏:

#define StrongSelf  __strong  __typeof__((__typeof__(self))self)
#define WeakSelf    __weak    __typeof__((__typeof__(self))self)

#define RecoverSelf  for (BOOL _continue_loop = YES; _continue_loop; _continue_loop = NO)              \
                     for (StrongSelf this = self; this != nil && _continue_loop; _continue_loop = NO)  \
                     for (StrongSelf self = this; _continue_loop; _continue_loop = NO)
#define WeakenSelf   for (BOOL _continue_loop = YES; _continue_loop; _continue_loop = NO) \
                     for (WeakSelf   this = self;  _continue_loop; _continue_loop = NO)   \
                     for (WeakSelf   self = this;  _continue_loop; _continue_loop = NO)

你可以这样使用:

WeakenSelf {
    _signupBlock = ^{
        RecoverSelf {
            NSLog (@"%d", self.property)
            NSAssert((self.property > 5), @"Some message");
        }
    }
}

NSAssert 只应在 Objective-C 方法中使用,因此它使用 self_cmd。块不是 Objective-C 方法,因此您不应在其中使用 NSAssert。您可能应该改用 NSCAssert