using variables in a block from a parallel scope
-
07-06-2021 - |
Question
__block BOOL myBool = NO;
__strong MyClass *ptr = self;
self.footer.defaultSelectedItem.selectionBlock = ^{
myBool = YES;
ptr = nil;
};
This works just fine when my Scheme's Build Configuration is set to Debug, but I get an EXC_BAD_ACCESS
when I run with Release. The EXC_BAD_ACCESS
happens on the the following line
if(selectionBlock != nil) selectionBlock();
but if I comment out all the lines inside my selectionBlock
then it runs with no error. Why does this run in Debug and not Release?
FYI I'm using Automatic Reference Counting (arc)
** EDIT in response to @RobNapier **
The original code that works in debug is:
__block BOOL flag = NO;
__strong EventsView *ptr = self;
self.footer.defaultSelectedItem.selectionBlock = ^{
if(flag) return;
flag = YES;
[ptr backTUI:nil];
flag = NO;
};
Solution 2
For the life of me I could not get this to work with a block. So instead I moved to using a setter for the Event View pointer. I'm guessing that fixed the problem with my pointer by setting up an additional ARC retain. I'm still uncertain because I never saw a zombie get logged when using the block so yeah.
When in doubt, use a selector.
OTHER TIPS
There's no reason for the extra ptr
here. Using self
inside the block would be more correct. The block will retain self
in that case. That may cause a retain loop, so it's up to you to remember to set self.selectionBlock = nil
at some point before dealloc
to break the retain loop.
flag
may be optimized away here. It's not clear how it could possibly be useful from the above code.
I'm always very nervous about long indirection-chains in a set operation like this one:
self.footer.defaultSelectedItem.selectionBlock = ...
I would make sure that footer
, and the current defaultSelectedItem
can't disappear before this runs.
Simplify the problem. Make the block just log "Running block." Then add back things until it crashes.