Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C: Blocks vs. Selectors vs. Protocols

Tags:

objective-c

I frequently find myself writing "utility" classes that can be re-used throughout my projects.

For example, suppose I have an "Address Book" view. I might want to use my address book to select who gets sent an email, or maybe who gets added to a meeting request.

I'd develop this view controller so it can be used by both the email controller, and the meetings controller, with some sort of callback mechanism to let the caller know the user either finished selecting someone from the address book, or they canceled.

It seems there are basically four (reasonable) approaches one might take in this scenario;

  • Create an "AddressBookDelegate" protocol and a corresponding delegate property on the AddressBookController. Then use the messages defined in the protocol to communicate the result (similar to UIActionSheetDelegate).

  • Create an "informal" "AddressBookDelegate" protocol and a corresponding delegate property on the AddressBookController, but the type of the delegate property will be "id", and will check at runtime with "respondsToSelector:" to see if the delegate implements the methods we require (seems like most of the framework stuff has started going this way).

  • Pass the AddressBookController an id that represents a delegate, as well as two SELs which specify the methods to call when the user selects a user or cancels the request. The benefit I see with this is; suppose one controller supports BOTH sending emails AND setting up meetings (I know in this example that seems like bad design... but one can imagine a more generic situation where this would seem perfectly reasonable for a utility class) - In this case you could pass the AddressBookController different SELs depending on whether you're adding users to an email, or adding users to a meeting... a huge improvement over an iVar to indicate the controller's "state".

  • Pass the AddressBookController two blocks; one to run when the user selects someone from the address book, and one to run if the user cancels the request.

The blocks have been so tremendously useful to me, and SO much more elegant, I'm finding myself almost confused over when to NOT use them.

I'm hoping more experienced members of the StackOverflow community than I can help out with their thoughts on this topic.

like image 234
Steve Avatar asked Aug 03 '10 01:08

Steve


1 Answers

The 'traditional' way to do this is with a protocol. Informal ones were used before @protocol was added to the language, but that was before my time and for at least the last few years informal protocols have been discouraged, especially given the @optional specifier. As for a 'delegate' which passes two SELs, this just seems more ugly than declaring a formal protocol, and generally doesn't seem right to me. Blocks are very new (esp. on iOS), as these things go, and while we have yet to see the tremendous volume of documentation/blogs on the best tried and true style, I like the idea, and this seems to be one of the things blocks are best for: neat new control flow structures.

Basically what I'm trying to say is that each of these methods vary in age, with none being better than the last except for style, which obviously counts for an awful lot, and is ultimately why each of these things was created. Basically, go with the newest thing you feel comfortable with, which should be either blocks or a formal protocol, and that your confusion is most likely coming from reading conflicting sources because they were written at different times, but with time in perspective, it is clear to see which supersedes the others.

[Controller askForSelection:^(id selection){   //blah blah blah } canceled:^{   //blah blah blah }]; 

is probably a hell of a lot more concise than defining two extra methods, and a protocol for them (formally or otherwise) or passing the SELs and storing them in ivars, etc.

like image 197
Jared Pochtar Avatar answered Oct 08 '22 04:10

Jared Pochtar