Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nil checking on blocks [duplicate]

I have a method that does an asynchronous network call, and then passes the success or failure results back via blocks:

- (void) loginWithSuccess:(void (^)(id responseObject))success failure:(void (^)(NSError* error))failure {
...
  if(error) {
    failure(error);
  }
  else {
    success(responseObject);
  }
}

I noticed that if I call this method and pass in nil as my blocks, my application will crash with EXEC_BAD_ACCESS:

[manager loginWithWithSuccess:nil failure:nil];

But, if I pass in empty blocks, it runs fine:

[manager loginWithWithSuccess:^(id responseObject){} failure:^(NSError *error){}];

I assume this is because at runtime you can't pass parameters to nil? So, when defining my methods that take blocks, should I always check that the blocks are not nil before calling them?

like image 795
hodgesmr Avatar asked Oct 21 '22 16:10

hodgesmr


1 Answers

Just looking at Apple's Frameworks, some methods with block parameters accept NULL/nil as the block argument (e.g. animateWithDuration:animations:completion:), others don't (e.g. enumerateObjectsUsingBlock:).

If you're designing an API, you have to make that decision. If it makes sense to not have a block, you should accept nil and check before executing the block, otherwise you should throw an assertion like [@[] enumerateObjectsUsingBlock:nil] does:

'NSInvalidArgumentException', reason: '*** -[NSArray enumerateObjectsUsingBlock:]: block cannot be nil'

So why are you getting EXEC_BAD_ACCESS?

When invoking a block you are dereferencing the address, which you obviously can't do if it's not pointing to an actual block. There is a great explanation in this answer.

like image 186
Sebastian Avatar answered Nov 02 '22 23:11

Sebastian