0

I have an instance method that I'd like to invoke directly using the callback param from a block in objective-c. I prefer this approach when I need to do more than a simple 1 liner in the callback.

Here is the basic setup...

I init a class w/ some type of call back so I can parse json after the http request lets say

- (void)initFooAndDoStuff {
    Foo *foo = [[Foo alloc] initWithCallback:^(NSData * response){
        // do stuff
    }];
}

//this is the instance method I'd like to invoke instead of an inline function
- (void)callBackWithHttpResponse:(NSData *)response {
    // do stuff ... assuming it's more complex than a 1 liner that is
}

I can setup a call back that does something inline (but again more complex stuff would be better in a stand alone instance method perhaps)

Foo *foo = [[Foo alloc] initWithCallback:^(NSData * response){ 
    NSLog(@"foo"); 
}];

I can use the instance method like below but it feels a little long winded. Any way I can cut this down (the syntax that is).

Foo *foo = [[Foo alloc] initWithCallback:^(NSData * response){ 
    [self callBackWithHttpResponse:response]; 
}];
4
  • I don't understand what you're trying to do. Do you want to declare one block and copy or reuse it again and again instead of having to re-declare it inline each time? Commented Jun 16, 2012 at 22:36
  • Blocks are generally less cumbersome than the old target-and-selector technique that predated them. Your last code snippet is pretty concise and simple, I think. If you want to do the target-and-selector approach, then design Foo to work that way. Commented Jun 16, 2012 at 23:29
  • @Ken can u show and example of this? Evan would the delegate syntax reduce the noise I'm talking about? Commented Jun 16, 2012 at 23:32
  • Foo might define - (id) initWithTarget:(id)target callbackSelector:(SEL)selector. It would save the target and the selector in ivars. It would be called like [[Foo alloc] initWithTarget:self callbackSelector:@selector(callBackWithHttpResponse:)]. To call the callback, Foo would do [_target performSelector:_selector withObject:response]. Commented Jun 16, 2012 at 23:37

2 Answers 2

2

If you're going to put the implementation in a method, you might as well just have the method return the entire block:

-(void (^)(NSData *))httpResponseHandler {
    return ^(NSData *responseData){
        // do something with responseData
    };
}

Then the places you use it would be a bit more succinct:

Foo *foo = [[Foo alloc] initWithCallback:[self httpResponseHandler]]; 
Sign up to request clarification or add additional context in comments.

4 Comments

awesome! this is exactly what I was looking for! (funny I ended up on your blog this morning after some issue with ocmock. Keep up the great objective-c / iOS mentoring **we need more developers like yourself in the community)
I'm not really sure how that is a simplification -- more of a lateral move in terms of complexity -- but it certainly is a perfectly valid (and useful -- I do similar things all the time) pattern. Upvote!
@bbum I agree, not a simplification per se, depends a lot on how you might re-use the implementation--the callback method embedded in inline block is probably more flexible overall. But I do like to return blocks from methods as a design practice where it's relevant.
I dont know if its valid/accepted way to use this pattern, but i use it to free up delegate methods for cleaner code. Example: If there is much communication between VCa and VCb, i send a dictionary from VCa to VCb containing all the methods VCb needs to call on VCa. So instead of cluttering up the VC-chain with delegate call backs, VCb can just call the methods stored in the dictionary. This keeps "encapsulation" i think? and it reduces multiple delegate methods to only one. Maybe you guys can comment if this is a bad idea?
1
Foo *foo = [[Foo alloc] initWithCallback:^(NSData * response){ 
    [self callBackWithHttpResponse:response]; 
}];

OK -- pretty darned readable as it is.

Now, go in the other room and hit yourself in the head 3 times with a brick to simulate not having looked at this project in 6 months to a year.

Now, read the code again.

Still readable, isn't it?

There is nothing wrong with a bit of verbosity when that verbosity says exactly what the code is doing. You could go with a target/action pattern as Ken Thomases suggested, but that would require additional complexity elsewhere.

Instead of callback, I would change it to be even more specific. I.e. if the callback was really a completion handler:

Foo *foo = [[Foo alloc] initWithHTTPResponseCompletionHandler:^(NSData * response){ 
    [self httpResponseCompletionHandler:response]; 
}];

1 Comment

I'll agree -the complexity on the other end appears to be > what I'm already doing when I alloc/init the web service class. I was simply curious to see what other options I had as I'm fairly new to objective-c block syntax (thanks for the replies)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.