I created a library that can load JSON data, which is then placed in an NSDictionary. I wrap this class with a simple Twitter engine that allows me to pull out the timelines of my friends, post an update and post an update with my GPS location. From my limited experience with Objective-C, the way to connect to everything is related to delegation. I set a delegate property that returns an asynchronous result to either the selector or the method. I can even create an optional or required interface for the delegate that will allow Xcode to help me a bit in implementing delegation. To learn about using delegates in Objective-C, I created this simple project.
http://www.smallsharptools.com/downloads/ObjC/Delegates.zip
It defines a Worker class that allows you to initialize a class with a delegate. When work is done using the doWork method, it looks for the method signature in the delegate to send the message back to. It uses the following code.
if([[self delegate] respondsToSelector:@selector(workFinished:)]) { NSString *msg = @"That it? Easy!"; [[self delegate] workFinished:msg]; }
He is looking for the workFinished: method to send a message. I declared this method signature as an optional interface with the following code in the header, Worker.h.
@protocol WorkerNotifications @optional - (void) workFinished: (NSString *) msg; @end
You can see the rest of the project from the download for all the details. But these 2 code snippets show how this delegation pattern works. But with the Twitter class, I need to know the context of the method that triggered the asynchronous action, which results in a callback to the delegate method. If I call the sendUpdate method more than once from the calling class, how should I know the callback context?
Usually with a language like JavaScript, Java or C #, I would create a built-in closing or anonymous class that would have access to the original context, but this is not currently possible with Objective-C on the iPhone. I found that this question has already been asked and answered StackOverflow.
Anonymous delegate implementation in Objective-C?
So, I did skip the optional interface and instead passed it to the selector, which the Twitter class will call when the asynchronous action is completed. The call to start this action is as follows:
CMTwitterEngine *engine = [[CMTwitterEngine alloc] initWithDelegate:self]; [engine setSendUpdateFinished:@selector(sendUpdateFinished:)]; [engine setSendUpdateFailed:@selector(sendUpdateFailed:)]; [engine setParsingSendUpdateFailed:@selector(parsingSendUpdateFailed:)]; [engine setUsername:TWITTER_USERNAME pass:TWITTER_PASSWORD]; [engine sendUpdate:statusUpdateText.text];
This code first initializes a link to the engine using self as a delegate. To attach callbacks, I send in selectors that I originally used on the signature of the sendUpdate method, but the method calls are quite long. I decided to just set the properties of the selectors. It all works, but I'm not sure I like the way it works, since it only partially solves my problem.
To complete this example, I end the asynchronous operation and end up calling the method inside, which searches for the given selector and calls it if one is defined.
- (void)sendUpdateFinished:(NSDictionary *)dictionary { if (self.sendUpdateFinished != nil) { [self.delegate performSelector:self.sendUpdateFinished withObject:dictionary]; } }
I can send the status message for sending as a Twitter update, but I still do not have the context of the outgoing call. What if I want to call sendUpdate more than once and the first asynchronous call is still running? But what if the second call ends first? Both of them will act as a delegate, so I will either have to track the context in some way, or pass them to another selector to distinguish them, which also does not satisfy my needs. What happens if I have 3 or 4 or 5 asynchronous calls? I need to know which of them were sent successfully and when they were completed.
It seems the only way I can do this is to create a class that contains all the properties necessary for the context, include this class as a delegate to call the asynchronous Twitter method, and then report back to the parent class, which is most likely the UIViewController . I would take this approach, but I have not read about this approach or have I seen any example code that does this.
What would you do? How would you deal with several asynchronous calls that could end in a different order than going out and then processing them with context after completion?