views:

546

answers:

3

Hi guys, I have a class that calls another class to parse (NSXMLParse) from a URL. Now I would like for the class calling this one to know when it has finished, so that I can populate the UI. I am guessing a delegate would be the way to go but ive never worked with one and would need some guidance as to how this would be wired.

Thanks

+3  A: 

Basically, delegation just means giving an object a pointer back to something that it needs to tell about what it's doing. In Cocoa, this is usually handled through “protocols”, which are sort of the reverse of an interface declaration: they describe what methods an object will call on another object that “implements” the protocol. They're not, strictly speaking, necessary, particularly in a simple situation like this, but they're good practice and a good thing to know if you're going to be writing modular code.

In the parsing class's header:

 // This is the protocol declaration; anything implementing the "ParsingDelegate" protocol needs to have any method signatures listed herein
 @protocol ParsingDelegate
 - (void)parsingDidEndWithResult:(NSDictionary *)result
 @end

 @interface ParsingClass : NSObjectOrWhatever
 {
      ...
      id<ParsingDelegate> _delegate;
 }
 ...
 // We'll use this property to tell this object where to send its messages
 @property(nonatomic,assign) id<ParsingDelegate> delegate;
 @end

In the parser's implementation:

 @implementation ParsingClass
 @synthesize delegate=_delegate;
 // the "=_delegate" bit isn't necessary if you've named the instance variable without the underscore
 ...

In the method in which the parser finishes its stuff:

 ...
 // make sure the delegate object responds to it
 // assigning an object that doesn't conform to the delegate is a warning, not an error,
 // but it'll throw a runtime exception if you call the method
 if(self.delegate && [self.delegate respondsToSelector:@selector(parsingDidEndWithResult:)])
 {
      [self.delegate performSelector:@selector(parsingDidEndWithResult:) withObject:someResultObject];
 }
 ...

In the UI class's header:

 @interface SomeUIClass : NSObjectOrWhatever <ParsingDelegate>

In the UI class, wherever it sets up the parser,

 parser.delegate = self;

then just implement the -parsingDidEndWithResult: method on the UI class. If you have multiple parsers running at once, you might want to extend the delegate method to pass in the parser object itself—that's kind of the Cocoa standard—but for the case you've described, this should do the trick.

Noah Witherspoon
Thanks for your detailed explanation. must be the most concise and yet detailed explanation so far. I have tons of books and it still doesnt explain it as clearly. Cheers
Doron Katz
Only issue i have is there are two warnings:(1) respondsToSelector not found in protocol(2) performSelector not found in protocol.Are we missing something in the protocol declaration mate?
Doron Katz
You're right—`-respondsToSelector` and `-performSelector` are both methods on `NSObject`, and obviously don't apply to `id`, which kind of doesn't have an interface. I think `id<NSObject,ParsingDelegate>` would be the correct syntax for declaring that an object must adhere to multiple protocols.
Noah Witherspoon
+1  A: 

You mainly got 3 ways to talk in cocoa: delegates, notifications and KVO. (cf http://alexvollmer.com/index.php/2009/06/24/cocoas-ways-of-talking/)

I assume that you are fetching the data and parsing the XML in a background thread. So whatever solution you are going to use, keep in mind to update the UI in the mainthread (using performSelectorOnMainThread for instance)

nico
+4  A: 

NSNotification is, in my opinion, the easiest way to setup something like this.

This is a small snippet from one of my apps:

in method.m when the something I'm processing has finished

[[NSNotificationCenter defaultCenter] postNotificationName:@"GlobalTagsReady" object:nil];

in the class to take care of the notification

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getTags) name:@"GlobalTagsReady" object:nil];

where @selector(getTags) is the method to be called

James Raybould
Another good point, this does seem easier but whats the best practice method, Notifications or delegates?
Doron Katz
Notifications tend to be used when you got multiples unrelated listeners, and delegates when you got one-to-one relationships.
nico