Implementing Delegate Pattern in Objective-C - iphone

I am building a class that handles NSURLConnection requests. To allow other classes to use this class, I would like to allow the main class to call a delegate when connectionDidFinishLoading is fired.
I've looked through lots of documentation, but I can't find anything that gives any clear examples, and the code that I have doesn't call the delegate for some reason. The code I have so far is (code not relevant removed):
Interface:
#interface PDUrlHandler : NSObject {
id delegate;
}
- (void)searchForItemNamed:(NSString *)searchQuery;
#property (nonatomic, assign) id delegate;
#end
#interface NSObject (PDUrlHandlerDelegate)
- (void)urlHandler:(PDUrlhandler*)urlHandler searchResultsFinishedLoading:(NSDictionary *)resultData;
#end
Implementation:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Fininshed Loading...");
resultData = [self parseJSON:jsonData];
if(delegate && [delegate respondsToSelector:#selector(urlHandler:searchResultsFinishedLoading:)]) {
NSLog(#"Delegating!");
[delegate urlHandler:self searchResultsFinishedLoading:resultData];
} else {
NSLog(#"Not Delegating. I dont know why.");
}
}
The delegate within the other class:
- (void)urlHandler:(PDUrlhandler*)urlHandler searchResultsFinishedLoading:(NSDictionary *)resultData;
{
NSLog(#"Delegating!!!!");
}

My first thought was you might not have set the delegate, but you have. Other than that, the code looks correct. Can't see anything wrong. Did you try and put a breakpoint at the place where you are checking whether your delegate responds to a selector? Could be that the delegate value was not retained and became nil. Make sure your delegate is not nil and has the correct object.
Also are you sure the connection is asynchronous? Synchronous connections will not call the connectionDidFinishLoading method

Turns out I forgot to set the delegate:
[currentHandler setDelegate:self];
needed to go after the line that makes the initial call to the PDUrlHandler.

For anyone interested in seeing an example of this the apple sample application NSURLCache implements a simple delegate around an NSURLConnection in NSURLCacheConnection.m
The sample app is available through the apple developer connection here:
http://developer.apple.com/iphone/library/samplecode/URLCache/index.html
I found it pretty useful.

You're on the right track, the way you're implementing the delegate pattern looks okay. The reason it's not being called is because you're using the wrong method signature in respondsToSelector; you have humidorServer:searchResultsFinishedLoading: when you actually want urlHandler:searchResultsFinishedLoading:.

Could it be the semi colon at the end of the method name in the delegate (bottom code sample on the far right)? If the delegate is set and the -connectionDidFinishLoading: method is being called then I can't see anything wrong

Since you tagged this with "iphone", I assume you're working on an iPhone app and don't need to support OS X pre-10.5. In Objective-C 2.0, Apple suggests you use formal protocols (using #protocol) with optional methods instead of informal protocols. Here's the relevant text:
Being informal, protocols declared in
categories don’t receive much language
support. There’s no type checking at
compile time nor a check at runtime to
see whether an object conforms to the
protocol. To get these benefits, you
must use a formal protocol. An
informal protocol may be useful when
all the methods are optional, such as
for a delegate, but (on Mac OS X v10.5
and later) it is typically better to
use a formal protocol with optional
methods.
(source)

Related

Is there a way to send an object via Delegates in Objective-C

I have a scenario, where I am waiting for a uiwebview to get fully loaded and then a delegate called from finishedWebViewLoading once completed. However, I want to return that webView when finished loading as an object which is a private object to another Class. Is there anyway to do that through delegates? I don't want to have that uiwebview as a public property, hence I have utilized it under my main file.
Thanks.
sure you can do it like this .. in .h
#protocol yourClassProtocal <NSObject>
- (void) loadingFinsihForWebView:(UIWebView*)wv;
#end
and in the webView Delegate webViewDidFinishLoad
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[delegate loadingFinsihForWebView:webView];
}
I am not sure I understand what you are asking, but you cannot return any value from (void)webViewDidFinishLoad:(UIWebView*)webView, nor can you change the delegate signature.
On the other hand, if you mean that you are going to call another custom delegate method from webViewDidFinishLoad, and that you want that it returns the webView, then this is definitely possible. Simply call that custom delegate method and pass the webView to it, then make the custom delegate method return it.
This assumes you are in charge of the definition of the custom delegate method signature, e.g.:
#protocol CustomDelegateProtocol
- (UIWebView*)myCustomDelegateMethod:(UIWebView*)view;
#end
The answer to your question is: YES.
However, I believe you might need to read up on how delegates work and how to create them, this post might get you on the right path getting there: How does a delegate work in objective-C?
Also, have a look at this article: http://blog.shoguniphicus.com/2011/10/17/writing-custom-delegate-in-objective-c/
You can use this:
if([self.theDelegate respondsToSelector:#selector(loadData:)]) {
[self.theDelegate performSelector:#selector(loadData:) withObject:theObject];

declaring methods in my header file

easy question to ask, but not really sure what to search for to find an answer for this one.
do I have to declare the method
- (void) applicationWillResignActive:(NSNotification *) notification;
in my header file? I'm trying to build my first app and im just going through trying to clean up my code.
Thanks!
No you don't have to. These are methods that will allow you to perform certain actions in some conditions, in the case of this one is when your application is about to go to the background. If you don't implement it nothing will happen. It is the same as with "viewWillAppear" and so on.
Also those methods only have to be implemented in the .m file since they come from the parent class. Since you are probably placing it in an object that comes from an UIViewController subclass.
The method applicationWillResignActive: is an optional method in the UIApplicationDelegate protocol. Your app delegate should already have declared that it conforms to that protocol in its header. So since it is already declared you don't have to declare it again.

How to test a protocol for a method?

Before iOS 4, I used to add a observer to each MKAnnotationView added to the map view, listening for it's selected method, so I know when the user has tapped on a pin.
This worked fine up to iOS 4.2. I've noticed on the release noted annotation views are actually being reused and it somehow messes up with the observers.
So I figure I can use the -mapview:didSelectAnnotationView: method from MKMapViewDelegate for my needs, but that has only been added to iOS 4.0 SDK.
So, to maintain compatibility, I'd like to implement this method on my delegate and conditionally check for the presence of this method on the MKMapViewDelegate protocol so that if it's not present, I will add my observer to the annotation view.
How can I do this for a protocol method, similarly for how we check if a class is not nil?
UPDATE:
As Daniel Dickison pointed out, I can't use respondsToSelector:, because my delegate has -mapview:didSelectAnnotationView: implemented for 4.0+ devices. What I need is to check if the protocol on that device has the optional -mapview:didSelectAnnotationView: method OR if MKMapView will look for that method on it's delegate.
I ended up doing a test for the current iOS version running. If it's higher than 4.0, MKMapView will look for that method and call it.
if ([[[UIDevice currentDevice] systemVersion] doubleValue] < 4.0)
[self setupObserver];
This solves the original problem, but it would still be interesting to check the actual protocol for the method somehow.
Because there is no object instance you can ask if it responds to a message selector, and you already know the protocol is supported but you are just looking for one method within - you need to use protocol_getMethodDescription, like so (method is class instance and optional) where you check for a nil return value:
#import <objc/runtime.h>
struct objc_method_description hasMethod = protocol_getMethodDescription(#protocol(MKMapViewDelegate), #selector(mapView:didSelectAnnotationView:), NO, YES);
if ( hasMethod.name != NULL )
{
...
}
That's a tricky one. So if I'm understanding your question correctly, you want to find out, at runtime, whether the map view sends the mapView:didSelectAnnotationView: message to its delegate. But you can't use conformsToProtocol: or respondsToSelector: because you're implementing the delegate so obviously you're adopting the protocol and implementing the method.
The only thing I can think of is to check for some other method that was added to MKMapView (not the delegate) in iOS 4, like: mapRectThatFits:.
Another possibility is to use the Objective-C runtime library to query the Protocol object. But this is probably overkill, and also I don't think it will work because the Protocol object is created by the compiler when you build your app, and it's possible you'll get the UIKit SDK-defined MKMapViewDelegate protocol object instead of whatever the runtime was compiled with.
I think you want NSObject conformsToProtocol - something like:
BOOL test = [myObject conformsToProtocol:#protocol(MKMapViewDelegate)];
I would use the respondsToSelector: method because that allows you to check for specific methods (which it sounds like you're doing, otherwise, if you're looking to check for a specific protocol, #Eric's answer is a good one). This SO post talks about using it this way.
Basically, the way you'd use it is
SEL methodName = #selector(mymethod:);
BOOL test = [object respondsToSelector:methodName];
I've taken a slightly different approach.
I simply use an #ifdef (__iPHONE_OS_VERSION_MIN_REQUIRED... and add observer if necessary, along with using the -mapview:didSelectAnnotationView: delegate method.

what do mean by "delegate" in iPhone application

I usually read a word 'delegate' in the apple document and their library book. What exactly meaning about this word? Any special meaning in iPhone?
Thank you very much.
Delegates are a design pattern in object-oriented languages that allow an object to "call out" to unknown code to perform activities or calculations that that object cannot effectively do on its own. Let's say you have a class Dog:
#protocol DogDelegate;
#interface Dog : Wolf <Domesticated>
- (void)bark;
- (void)tiltHeadAdorably;
- (void)playWithToy: (Toy *)aToy;
#property (readonly) Toy *favoriteChewToy;
#property (readwrite, assign) id <DogDelegate> delegate; // "DELEGATE" PROPERTY DECLARED HERE
#end
The delegate object is generally supplied by the code that instantiates Dog, and is called upon by that instance to do things that the dog itself can't do. For instance, consider this interface of the DogDelegate protocol, which defines what the Dog's delegate object is expected to do:
#protocol DogDelegate <NSObject>
#required - (void)letDogOut: (Dog *)aDog;
#required - (void)letDogIn: (Dog *)aDog;
#optional - (void)scratchDog: (Dog *)aDog forTimeInterval: (NSTimeInterval)duration;
#end
In this case, an instance of DogDelegate is often the owner of the Dog (and, in Objective-C, a delegate often owns an object, so this lines up nicely with the metaphor.) The dog, when it needs to go out for... dog activities... will ask its delegate to perform the -letDogOut: method, placing the dog in the backyard. When done, it will ask its delegate to perform the -letDogIn: method, bringing the dog back inside. When the dog wants affection, if its delegate is able to, it will ask the delegate to scratch it for some period of time using -scratchDog:forTimeInterval:.
Delegate is a Design Pattern that Apple adopts heavily. In a nutshell, think of it like "I'm responsible for handling ...". Where ... is a notification, event, protocol, etc. For example, your AppDelegate is responsible for your handling your App setup, display, launch.
Please keep in mind I am over simplifying it. But I am sure someone can provide a much more detailed answer if you need.
A delegate is the same thing as a callback function in JS ( the exception being that delegates are type-safe.) For example, if you're doing Ajax in JS, you declare a callback function to be called when the Ajax call is finished. In this same fashion, you would declare a delegate function to be called, for example, when a song selection dialog is closed.
Delegate is a object that controls the whole application. It shows the main window and will tell the app what to do when it is launched and closed. It is basically the command center of your app. The best way to use this is to call other controllers to display some NIBS. There really isn't anything special about a delegate in an iPhone app, but there are special methods that are called.

Do I have to specify a protocol if I want my class to have a delegate?

I'm new to Objective-C and development on Apple's platforms, but hopefully I can frame this question in an understandable way regardless :)
I want to parse an XML feed for my iPhone app, and I decided instead of shoving all of the delegation methods from an instance of NSXMLParser into my view controller, I'd wrap this up inside of a FeedParser class. After reading a few docs and example code, here's what I came up with:
#protocol FeedParserDelegate <NSObject>
- (void)parserDidLoadEpisodes:(NSArray *)episodes;
#end
#interface FeedParser : NSObject {
id <FeedParserDelegate> delegate;
}
#property (nonatomic, assign) id <FeedParserDelegate> delegate;
- (id)initWithURL:(NSURL *)url delegate:(id<FeedParserDelegate>)theDelegate;
#end
Simple. Delegates of my FeedParser object just have to implement parserDidLoadEpisodes.
However, as I started actually making my FeedParser class use NSXMLParser, I realized that I didn't have to specify that FeedParser implements a protocol for NSXMLParser -- I could just implement the delegate methods that I wanted to do something with. I think I've noticed this with other classes that follow the delegate pattern, too, but not all.
So why wouldn't I too just not bother with specifying a formal protocol for my FeedParser class? It would cut away some perhaps unnecessary code. I guess the question is: why would I want to create a formal protocol instead of just doing something like just checking to see if the method is implemented on the delegate with respondsToSelector? Is it only so that the compiler will issue nice warnings if a required delegate method isn't implemented?
A protocol declared with #protocol is called a "formal protocol". The other way to do it is to declare a category (a set of additional methods) on NSObject, like so:
#interface NSObject (FeedParserDelegate)
- (void)parserDidLoadEpisodes:(NSArray *)episodes;
#end
Then simply define that method for any object that you want to be a feed parser delegate, and leave it undefined otherwise. This is called an "informal protocol".
Why are there two ways? Well, here's a hint: the informal protocols came first. What it comes down to is that they added formal protocols because informal ones weren't cutting it. Informal protocols make it too easy to forget an important method or try to use an object as a delegate for something it's not designed to work with.
Basically, for the cost of adding <FeedParserDelegate> here and there, you can get the compiler to do your debugging for you. The compiler will generate warnings for the most common delegate bugs, which saves you time if you make one of those mistakes. Why not take advantage of its helpfulness?
Always, always, always favor compile-time error checking over run-time. You could of course ask the class if it supports the method, but why ask when you can know?
The answer is no, you don't have to. But you should want to. :)
Adding a protocol makes the compiler check things for you. If you don't get those nice errors at compile time, then you'll get them later at run time when they're harder to track down.