EDIT2:
No. The suggested answer is about async calls. I want & need synchronous calls, like in a normal, standard recursive call.
EDIT:
while
__unsafe_unretained void (^unsafe_apply)(UIView *, NSInteger) ;
compiles without warning or errors, it fails at runtime with a NULL stored into unsafe_apply.
However this:
- (void) applyToView: (UIView *) view {
UIColor * (^colorForIndex)(NSInteger) = ^(NSInteger index) {
return [UIColor colorWithHue: ((CGFloat) index / 255.0f)
saturation: 0.5f
brightness: 0.5f
alpha: 1.0f] ;
} ;
void (^applyColors) (UIView *, NSInteger index) = ^(UIView * view, NSInteger index) {
view.backgroundColor = colorForIndex(index) ;
} ;
void (^__block recurse_apply)(UIView *, NSInteger) ;
void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
applyColors(view, level) ;
[view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
recurse_apply(subview, 1+level) ;
}] ;
} ;
recurse_apply = apply ;
apply(view, 0) ;
}
compiles without warnings, but more importantly, actually runs.
But this is so ugly!
consider (colouring the view hierarchy, for exposing purpose ...):
- (void) applyToView: (UIView *) view {
UIColor * (^colorForIndex)(NSInteger) = ^(NSInteger index) {
return [UIColor colorWithHue: ((CGFloat) (index * 10.0f) / 255.0f)
saturation: 0.5f
brightness: 0.5f
alpha: 1.0f] ;
} ;
void (^applyColors) (UIView *, NSInteger index) = ^(UIView * view, NSInteger index) {
view.backgroundColor = colorForIndex(index) ;
} ;
void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
applyColors(view, level) ;
[view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
apply(subview, 1+level) ;
}] ;
} ;
apply(view, 0) ;
}
I get this warning:
/Users/verec/Projects/solotouch/SoloTouch/BubbleMenu.m:551:42: Block pointer variable 'apply' is uninitialized when captured by block
If I apply the suggested fix: Maybe you meant to use __block 'apply'
void (^__block apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
I then get: /Users/verec/Projects/solotouch/SoloTouch/BubbleMenu.m:554:13: Capturing 'apply' strongly in this block is likely to lead to a retain cycle
I tried various ways to tamper with the code and get rid of those warnings
__weak typeof (apply) wapply = apply ;
if (wapply) {
__strong typeof (wapply) sappy = wapply ;
wapply(subview, 1+level) ;
}
But things just get worse, turning into errors.
I ended up with this:
__unsafe_unretained void (^unsafe_apply)(UIView *, NSInteger) ;
void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
applyColors(view, level) ;
[view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
unsafe_apply(subview, 1+level) ;
}] ;
} ;
unsafe_apply = apply ;
apply(view, 0) ;
Anyone has a better solution, where I could do everything from within the block and not hideously back patch it as I had to do here?
Note Those SO Questions are about capturing self
and those SO questions don't have any satisfactory answer.
The answer is no.
We can't seem to do better than using the __block qualifier.
Thanks to Bill Bumgarner article about blocks.
EDIT:
seems to be the preferred way under ARC.
To avoid ARC warnings and building on @newacct 's answer, I found that setting the weak block inside the retained block works:
You need to capture a
__block
variable, because blocks capture non-__block
variables by value when they are created, and the assignment happens after the block has been created.In ARC,
__block
variables of object pointer type (generally all variables are implicitly__strong
) are retained by the block. So if the block captures a__block
variable pointing to itself, it would create a retain cycle. The solution is to have it capture a weak reference. In versions of the OS that support__weak
,__weak
should be used instead of__unsafe_unretained
.However, if the only reference to the block was a
__weak
variable, there would be no strong references to the block, which means it can be deallocated. In order to use the block, it must have a strong reference to keep it around.Therefore, you need two variables, one weak and one strong. The proper way to do it in ARC is: