我想知道问题主题的变量声明是否合法。想象一下以下代码:
__weak typeof(self) weakSelf = self;
[self doSomethingThatMayCauseRetainCycleWithBlock:^{
typeof(self) self = weakSelf; // <---- !!!!
if (self == nil) return;
NSAssert(self.someProperty != nil, @"This doesn't lead to retain cycle!");
[self doSomething];
self.someProperty = someValue;
// even
self->someIvar = anotherValue;
}
此代码在Xcode 4.5.2中完美运行,仅发出警告Declaration shadows a local variable
。
这个怪癖有什么意义:
self
作为弱变量的强引用,您可以安全地复制/移动块内部/外部的代码而不会有偶尔创建保留周期的风险(除了ivars,但它们是邪恶的) NSAssert
不再导致保留周期。 更新
我发现libextobjc
用于@weakify/@strongify
宏的这种技术。
答案 0 :(得分:5)
这个答案分为两部分:
GCC_WARN_SHADOW
的替代你得到的警告来自NSAssert
,这是一个更无用的警告(无论如何,在我看来)。编译器在这里做了正确的事情,但是感谢GCC_WARN_SHADOW
它引起了你的注意可能做了一些你想做的事情。
这是偏执狂编译器警告擅长的事情。缺点是很难(不是不可能)放弃一个特定的警告,表明你知道你在做什么。
启用GCC_WARN_SHADOW
后,此代码将生成警告:
GCC_WARN_SHADOW
尽管如此,它仍将完美运作。
这样做的原因是它编译成这个,这很难看,但(对编译器)非常清楚:
int value = MAX(1,MAX(2,3));
所以你提出的建议会很好。 ({
int __a = (1);
int __b = (({
int __a = (2);
int __b = (3);
__a < __b ? __b : __a;
}));
__a < __b ? __b : __a;
})
是使用使用NSAssert
变量的宏实现的。如果您在范围内定义self
,则会选择self
。
但是,如果您认为self
有用,那么还有另一种解决方案。无论如何它可能会更好:提供你自己的宏。
GCC_WARN_SHADOW
这实际上是#define BlockAssert(condition, desc, ...) \
do { \
__PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
if (!(condition)) { \
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
object:strongSelf file:[NSString stringWithUTF8String:__FILE__] \
lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \
} \
__PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
} while(0)
的复制粘贴,但它使用NSAssert
而不是strongSelf
。在你use the strongSelf
pattern的地方,它会起作用;在未定义self
的地方,您将收到编译器错误:使用未声明的标识符:'strongSelf'。我认为这是一个非常好的提示。
答案 1 :(得分:3)
严格来说,您的代码没有任何问题 - 变量声明是合法的。但是,您可能会收到有关局部变量影响实例1的编译器警告。
GCD块实际上是C函数,而不是Objective-C方法。编译时,每个Objective-C实例方法都会添加一个额外的参数,即self
指针。 self
不像其他变量一样存储在对象结构中。
出于这个原因,我会毫不犹豫地在我要分享的库中使用此代码。代码可能会破坏当时编译器的新版本,因为实际上你会比运行时更明显地攻击运行时。另外,它是古怪的代码,正如你所指出的那样:)我不确定阅读它的其他人会立即明白发生了什么。