1

Solution:

Turns out the problem doesn't exist in this code. It's because the foo is being called in a UIViewController when it's being destroyed. Thus, when the asynchronous foo calls the completion block, it breaks due to a call to something that no longer exists.

Apologies to those whose time I took up with this. :/ Hopefully this will be a lesson to others to make sure their completion handler still exists at the time of completion.


Before I begin, I've looked at Wait for many asynchronous calls to perform callback and Chaining Completion Blocks, but the solutions in both do not fix my problem.

Situation:

I've got a method, foo, that has a completion block, but it calls another method, bar, with a completion block. foo calls its completion block during bar's execution of the completion block. An example is below.

-(void) foo:(void(^)())completion{
    ...
    bar:^{
        ...
        completion();
    }
}
-(void) bar:(void(^)())completion{
    ...
    completion();
}

When I do this, I get a bad access in foo's call to completion.

Do I need to make a __block copy of foo's completion parameter?

If so, how do I make it since __block (void(^)()) completionCopy; doesn't even pass the compiler?

Community
  • 1
  • 1
DrDisc
  • 281
  • 4
  • 12
  • 2
    Is neither block stored in a property at any time? What runs asynchronously? – Wain Aug 13 '13 at 14:47
  • 2
    Generally this construct is fine (though I assume you meant to invoke `bar` with `[self bar:^{...}];`). You don't need to make a copy of `foo`'s `completion` variable. Perhaps you can tell us precisely which line is causing the exception ([exception breakpoint](http://developer.apple.com/library/ios/recipes/xcode_help-breakpoint_navigator/articles/adding_an_exception_breakpoint.html) might be useful here). But there's nothing wrong with the basic construct of completion blocks calling other completion blocks. BTW, if you're using `__block` variables anywhere, let us know ARC v MRC. – Rob Aug 13 '13 at 15:02
  • 1
    What @wain said; this is obviously pseudocode. What is the real code doing? Anything asynchronous? Show the real code. – bbum Aug 13 '13 at 15:38
  • It turns out it was because of where I was calling the code. This was to save game data to our servers, but it was called in a UIViewController when it disappeared. When the completion block got back, the view controller no longer existed. – DrDisc Aug 13 '13 at 16:49
  • The original code is also in 3 different files for the whole flow, but that is the basic structure of the calls. In actuality, the flow is: UIViewCont -> save game Service -> server webservice -> server response -> webservice completion -> save game completion -> UIViewCont that doesn't exist anymore. – DrDisc Aug 13 '13 at 17:00
  • 1
    @DrDisc: "the view controller no longer existed" So? That does not explain anything. If a block uses something, it retains it, unless it was `__block`. So in order for it to crash, you must be doing something wrong. – newacct Aug 14 '13 at 00:01
  • Hmm, then I'm not sure what is wrong. I put a `if(completion != nil) completion()` check in, and it seems to work now. And yes, the view controller calling `foo:` calls it with a nil completion block. – DrDisc Aug 14 '13 at 13:53

0 Answers0