views:

270

answers:

3

Maybe it's just the fact that I've been using http://nodejs.org/ lately, but the lack of closures in Objective-C (iphone) has been really hard to work around.

For example, I'm creating service classes. Each service class can have several methods, each of which makes a different URL request. I can use the delegate pattern, but that means that I have to create a new service each time I want to call a method on it (because it has to store the delegate and selector for that request, and new method calls would overwrite them).

Even more difficult for me is the fact that I can't easily keep local variables around in the scope for a callback. I have to store anything I want to send back to the delegate on the service class itself, which makes it harder to have more than one method on each class.

How do you pros do it? Should I just quit whining and do it another way?

+9  A: 

Blocks, that were introduced into Objective-C recently, enable closures. The only problem is that you can't use them on iPhone. Here comes 3-rd party solution, Plausible Blocks - they bring this capability on iPhone too.

Update: the sample project using blocks on iPhone can be found here.

zakovyrya
If Plausible Blocks works, you will get my undying admiration forever....
Sean Clark Hess
I don't see any code samples on the PB site. They have exactly the same syntax as normal Blocks?
Sean Clark Hess
I used them in few projects already, but they didn't make it to App Store for various reasons. But since there is no use of private frameworks I'm sure Apple won't reject such application.
zakovyrya
Plausible Blocks is exactly the same as normal blocks — they essentially just ported Apple's compiler changes to work on 10.5 and the iPhone, so it's actually the same code. It works, but Cocoa Touch itself still won't have a lot of support for them (e.g. NSBlockOperation doesn't exist on iPhone, so you'll need to implement it yourself if you want it).
Chuck
@Sean Clark Hess - yes, exactly the same. I can send you the source code of test application that I've built while playing with them
zakovyrya
@zakovyrya - that would be great. No idea how to connect through SO. Can you post a link here or something? - github is a good place for that kind of thing
Sean Clark Hess
@Sean Clark Hess - uploaded project to github: http://github.com/zakovyrya/iPhone-blocks
zakovyrya
+7  A: 

Any time you find yourself needing multiple delegates, the answer is notifications.

For something like a service class you'd probably make a singleton, and notify interested parties when a service request was complete via a notification.

Not that blocks are not an interesting solution to that problem, it's just that I felt you should know there are alternatives.

Kendall Helmstetter Gelner
Huh... this is like the polar opposite of the approach I wanted to take (not that it's bad) because closures localize information, while notifications are completely global. Interesting.
Sean Clark Hess
I would argue that notifications are inherently local, because only the classes consuming them know they exist. They just happen to travel over a global bus... The same way singletons appear global, but you use them to isolate references to a pool of objects.
Kendall Helmstetter Gelner
Although it's a solution, I think it's more heavy-weight than using blocks, both in terms of coding and performance.
zakovyrya
Heavier in terms of performance, yes. But notifications can also be more flexible in that it's easy to add other listeners to react.I'm not sure it's that much different in terms of coding... it would be very interesting to set forth an example task and compare how you would do it using both mechanisms.
Kendall Helmstetter Gelner
@Kendall Helmstetter Gelner - In case of notification you essentially split the code into at least two logical units of the program - the one that registers for event, and the second - to process it, which will require little more effort for the code maintainer (usually there is also the context stored somewhere). On the small scale it's negligible, but can be a real pain for the full-blown application.When you assign a closure to some event, your code is nested in the same logical unit. The reader will have less problems following it.
zakovyrya
+1  A: 

I'm not a pro, but I've been struggling with the same problem so here's the best I've got so far:

@interface MyCallback : NSObject
  id target;
  SEL action;
  id value1;
  id value2;
  ...
@end

When I need to call something that will notify me about completion I fill set target and action with the actual callback (usually "self" and a method) and stuff other values I will need later into value1..2..3 The callee hangs on to the MyCallback object and when time comes it calls the target/action and passes the MyCallback as a parameter. That's how I get my "closure".

To address your other problem here's an idea: create a class derived from NSURLConnection, called MYURLConenction, and only addition is a field of type "id", call it MyStuff. Then proceed to use MYURLConenction instead of NSURLConnection - when you make a network request you can stuff your data (such as an instance of MyCallback) into MyStuff and it will hang on to them for you. Therefore you will not need to create a new instance of your service class for each invocation.

This is actually not how I do it though - I simply created a generic MyHTTPRequest wrapper class that is the delegate of the NSURLConnection, it accepts a URL & NSString POST body, processes all the network stuff and returns an NSString result and an NSError to the caller - a little bit higher abstraction. It also stores MyStuff, so that service classes can remain singletones if they want to.

DenNukem
Yeah, I've considered that approach. It works well, but having to cast and throw pass-through data on the callback is annoying. Although the example I gave might not be the perfect use-case, blocks really are the best way to have a callback keep variables around. Thanks!
Sean Clark Hess
Sure, blocks are better. Personally I'm just too shy to use hacked up compiler (god knows what kind of bugs are there) so I make do with existing tools.
DenNukem
What, you don't want random bugs popping up 6 months down the road? Where's your sense of adventure? :D
Sean Clark Hess