3

I have a singleton class the handle all the Game Center logic:

typedef void (^GameCenterCallbackFinishUpdating)();

- (void)getAllMatches:(GameCenterCallbackFinishUpdating)onComplete
{
    [GKTurnBasedMatch loadMatchesWithCompletionHandler:^(NSArray *matches, NSError *error)
    {      
        //Do stuff here... 
        onComplete();
    }];
}

From another viewController I use:

[[GameCenterHelper sharedHelper] getAllMatches:^{

    [self.myTableView reloadData]; 

}];

It works great when I'm in the app, but once I close the app (background) and then start it up again, I get:

    onComplete();     ---- Thread 1: EXC_BAD_ACCESS (code=2, address=0xc)

What am I doing wrong here?

BlackMouse
  • 4,442
  • 6
  • 38
  • 65

2 Answers2

10

some background info: the blocks are objects and if any block is nil and you try to call them, it crashes the application.

somewhere and somehow the block onComplete becomes nil before you call it. the following if (...) statement helps you to prevent to call a nil pointer, so the application won't crash.

if (onComplete) onComplete();
holex
  • 23,961
  • 7
  • 62
  • 76
  • 1
    The `blocks are objects` statement seems rather irrelevant, could you provide more context on how that information is relevant to the rest of the answer? – Paul.s Jan 11 '13 at 16:35
  • 1
    yes, it seems very relevant, because every object can be `nil` pointer, and the blocks are objects rather than functions or methods. what would you like to know about the block exactly? – holex Jan 11 '13 at 16:41
  • The terminology is a bit wrong there. An object can not be `nil`, but you can have a pointer to `nil`, as a result the more important fact here is that the variable `onComplete` is pointing to nothing. At this point it behaves like calling a function pointer that has been assigned `NULL` e.g. Crash – Paul.s Jan 11 '13 at 19:57
  • @Paul.s, yep, I agree with you, this terminology is not quite correct, because, as you said, the pointer can be `nil`. what I liked to tell here is many developers believe the block are like the function or methods and they never think the pointer to the block can be `nil` and somehow they have to manage this situation in the application. I just liked to show this important difference here, there are many more professional documentations of the blocks on the Apple official site. – holex Jan 13 '13 at 09:54
0

Thanks to @holex and @Paul.s for explaining it well. I had the similar situation where I was sending block as method parameter(completionHandler).

- (void)callX:(NSString *)xyz withCompletionHandler:(void (^)(NSString *response))completion
{
    completion(something);
}

And there are two situations either I am using this block like:

[MyClass sharedInstance] callX:@"abc" withCompletionHandler:^(NSString *response) {
    if (response) {
        //do something
    }
}];

or this block could be nil as method parameter:

[MyClass sharedInstance] callX:@"abc" withCompletionHandler:nil];

In second case when block was being passed nil as method parameter this caused EXC_BAD_ACCESS on completion(). So as @holex states that the blocks are objects and if any block is nil and you try to call them, it crashes the application. A single if saves lot of my time

- (void)callX:(NSString *)xyz withCompletionHandler:(void (^)(NSString *response))completion
{
    if (completion)
        completion(something);
}

P.S: this explanation only for NERDS like me. | ' L ' |

Muhammad Umair
  • 1,664
  • 2
  • 20
  • 28