I'm wondering is the variable declaration from the question topic is legitimate. Imagine the following code:
__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;
}
This code works perfectly in Xcode 4.5.2, only giving a warning that Declaration shadows a local variable
.
What's the point of this quirk:
self
as a strong reference to a weak variable, you can safely copy/move code inside/outside the block without a risk to occasionally create a retain cycle (except for ivars, but they are evil).NSAssert
in a block doesn't cause retain cycle anymore.Update
I discovered that this technique is used in libextobjc
for @weakify/@strongify
macros.
There's two parts to this answer:
GCC_WARN_SHADOW
, and why it's probably a bad warning to have turned on.NSAssert
that doesn't need this trickeryThe warning you're getting is from GCC_WARN_SHADOW
, one of the more useless warnings (in my opinion, anyway). The compiler is doing the right thing here, but thanks to GCC_WARN_SHADOW
it's drawing your attention to you possibly doing something other than you intended.
This is the sort of things the more paranoid compiler warnings are good at. The downside is that it's difficult (not impossible) to drop a particular warning to indicate that you know what you're doing.
With GCC_WARN_SHADOW
on, this code will generate a warning:
int value = MAX(1,MAX(2,3));
Despite that, it will function perfectly.
The reason for this is that it compiles down to this, which is ugly but (to the compiler) perfectly clear:
({
int __a = (1);
int __b = (({
int __a = (2);
int __b = (3);
__a < __b ? __b : __a;
}));
__a < __b ? __b : __a;
})
So what you're proposing will work well. NSAssert
is implemented using a macro which uses the self
variable. If you define self
in your scope, it'll pick up that self
instead.
But that said, if you think GCC_WARN_SHADOW
has a use, there's another solution. It might be better anyway: Provide your own macro.
#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)
This is essentially a copy-paste of NSAssert
, but it uses strongSelf
instead of self
. In places you use the strongSelf
pattern, it'll work; in places where strongSelf
is not defined, you'll get a compiler error: Use of undeclared identifier: 'strongSelf'. I think that's a pretty good hint.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With