I'm creating a service class in Objective-C that communicates with a HTTP server. I'm familiar with NSURLConnection and the associated classes to make an asynchronous request to a server. So far, I've used self as the delegate, responding to the four delegate methods (didReceiveResponse, didReceiveData etc.) required for the call.
The service class I'm building must be able to handle several requests at once, and respond differently to each. I'm looking for a way to achieve this, without an endless switch or if-elseif in the connectionDidFinishLoading method.
I have the idea to create a delegate class that implements the four methods described above, and give that to the NSURLConnection object to talk to. However, I want to notify the parent class when the connection finishes loading and then fire another method within the parent class. And of course, the delegate doesn't know which method this is - it could be anything.
How to proceed? Is there a way to set a selector for the delegate class, and fire that selector (which is a method) when the request is finished? How do I do such a thing?
(Creating a delegate for my delegate, and then calling a superclass method could do the trick, but I'm really looking into wildcard methods, such as a selector.)
Any help is greatly appreciated!
Regards,
Reinder
I would pass a block (^{ ... })to the delegate that it should call when the connection has finished.
You have three options:
Using a block callback
Using notifications
Using a delegate, as you already suggested.
All three are perfectly valid, but with various advantages/disadvantages. Learn them all, then decide which to use in each scenario. :-)
Often more than one solution will be chosen. For example many of Apple's classes implement a delegate method and send a notification for the same event.
Related
I was using method swizzling to wrap all method invocations in a class with some extra functionality. Specifically I was:
Checking if the required object for this method call was in the cache
If the cache had that object return it.
If not, dispatch to the original implementation, populate the cache and return that.
For each method, I would reroute to an advised method. And implement the new method using + (BOOL)resolveInstanceMethod:(SEL)sel and IMP_implementationWithBlock.
It worked fine, but the code didn't read nicely. It seems NSProxy will provide a neater way to implement this functionality.
But still another alternative, would be to simply have an NSObject subclass stand-in and intercept method calls around my target object's methods. By overriding forwardInvocation and methodSignatureForSelector, I can get the required outcome.
So what does NSProxy give me? Why should I use this instead?
The point of NSProxy is that it doesn't implement most methods. That's necessary to be sure that the Objective-C forwarding machinery gets invoked to begin with. If you start with NSObject, there are a lot of methods which will just be directly dispatched without you having an opportunity to forward them.
--UPDATE: I've decided to give AFNetworking a try. Even though RestKit has a really nice object mapping functionality, the way the networking calls were designed have made some things difficult for us.
I'm hoping for some advice on how to organize my project that's using RestKit.
I have several REST calls from a repository class and its results get passed to controllers. For example I have a getProfile method in the repository class that is getting called from our browse view controller. The view controller is set as the delegate to the get profile calls while the repository class is set to the delegate for the restkit calls.
The problem is if the browse controller makes several get profile requests, it is difficult to distinguish which result should go to which delegate function since all the restkit calls share the same delegate method objectLoaderDidFinishLoading. I then have 4 delegates that I have to match the results of the 4 asynchronous restkit requests.
Is there any way I can use blocks so that I can pass a function to execute as the asnynrhounous result comes back so that I can assign a proper delegate? The block support that I saw allowed a block to be used before the request was sent out in rest kit but I am interested in using it for when the asynchronous result is returned.
The alternative of examining the results or setting user data and sleuthing what delegate goes with what asynchronous results seems unreliable and bulky.
You can solve your issues with disambiguating between your profile requests by using the userData opaque pointer on RKObjectLoader. That will allow you to hang any object you want on the request, which can then be used to help distinguish between multiple profile requests. Also, if those profile requests are going to different resourcePaths then you can just use the wasSentToResourcePath: method on RKObjectLoader to distinguish between them.
I just stumbled upon this question while trying to figure out this problem for my own REST interface. I'm glad I did, I'll probably use RestKit now.
I digress, back to your question. As you noted it doesn't seem like the block argument in the RKObjectManager is meant to be used this way. Instead, how about writing a class that implements RKObjectLoaderDelegate, takes in a block, and calls that block on any of the delegate calls.
Maybe something like this?
#interface MyObjectLoaderDelegate : NSObject <RKObjectLoaderDelegate>
#property (nonatomic, copy) void (^callback)(RKObjectLoader *loader, NSDictionary *objectDictionary, NSError *error)
- (id)initWithCallback:(void (^)(RKObjectLoader*, NSDictionary*, NSError*)aCallaback;
#end
And on any implemented delegate method you can execute the block. Since blocks retain scoped variables you can run code against the calling delegate.
Whatcha think?
I am not sure using blocks is the right way to solve your issue.
How about having a class GetProfile that implements RKObjectLoaderDelegate.
So you call the request from within here and set itself to be the delegate.
Then you have an objectLoader per request.
So in your view controller, each time you what GetProfile, you create an instance. And then when that instance messages your controller back (via delegates?) you know which it is.
I am just grappling with this issue as well, so am keen to hear feedback.
Switching over to AFNetworking seems to be the way to go... it was a much easier implementation for what I needed.
Sorry for noobness-level of the question.
I saw this answer, where it says
Add something like this to your NSURLConnection delegate
However, the method in question, sendSynchronousRequest:returningResponse:error:, is a class method. If I understand delegate methods correctly, they use a delegate which is specified when the NSURLConnection object is initiated.
So, if I have no instance of the class, a delegate can't be used. Did I understand correctly?
Yes, you are correct. In Cocoa, assigning a delegate requires an instance. In the case of NSURLConnection, its delegate is supposed to be used when making an asynchronous request that is initiated with -initWithRequest:delegate: or +connectionWithRequest:delegate:
Since classes are also objects it could be conceived that they also could have delegates. However, since there is no concept of class variables in Objective-C, a class would have nowhere to store its delegate (it could use a standard C variable in its .m file, though). Anyway, this concept is not used in Cocoa.
Yes delegates are used for handling events when you send your request asynchronously.
While sending synchronous request using +sendSynchronousRequest:returningResponse:error: method delegates are not used - you only get the resulting data and (optionally) server response and error and not aware about intermediate loading events (and remember that calling thread is also blocked while connection is in progress).
I'm using the delegate pattern for one of my objects. My idea is that I will be able to swap the delegate out later for a different delegate implementing a different strategy. I suppose this is just as much the strategy pattern as the delegate pattern.
My question is, is it bad practice for my delegate to have a reference back to the object for which it is the delegate? There are a couple properties of that object that I need to have access to regardless of which delegate/strategy I use. If this is bad form, how should I get access to the properties?
Not necessarily. For example, it's quite common for a "controller"-type object to create data objects and views and make itself the delegate of some of those objects in order to properly control things.
It is not at all bad practice. The delegate pattern allows for a class to have a generic way to talk to any number of objects as long as the implement the same protocol. But the class on which you set the delegate also will usually have a number of public properties or methods that allow you to query or alter what the class is doing, in response to which the class may in turn trigger a number of the delegate calls. So you need a reference of the class to which you are the delegate, in order to tell the object to do something different than it is already, and of course to release it when you are through with it!
This is also why it's important to always have any delegate properties as assign, and not retain, properties. That way when the originating class is released it will actually be released, instead of having delegate objects it is holding onto causing a retain loop that keeps both around.
It's also why whenever you are being released, you should set the delegate reference to nil in anything you may have a delegate reference set. This way a class will not have an invalid delegate reference if the delegate is released before the class that uses a delegate.
Generally a dependency should not have a reference back to the dependent object, as this would be a classical circle reference. To avoid having a back-reference you can supply the needed properties as arguments in a delegate method, or you move the properties themselves into the delegate.
I'd say yes, it's bad practice. The idea behind a delegate is that it's effectively a standalone object that receives messages about the object for which it is the delegate (the "delegator"). The delegator should have a reference to the delegate, not the other way around, otherwise it's not a true delegation relationship anymore.
A preferred way to accomplish what you're asking is to provide the sending object along with whatever message your delegate receives. For example, on your delegate, instead of having a delegator property and then receiving, for example, a didDoSomething:(id)anObject method, you could remove the delegator property and send the message delegator:(id)anObject didDoSomething:(id)anotherObject. This way, you keep the delegate distinct from the delegator, but still get access to the delegator's properties when you need them.
This way also has the advantage of not providing access to the delegator in methods when you don't truly need it; for example, your delegate could have a didDoSomething method that takes no arguments, not even a delegator, and is just used for logging, as well as a delegator:(id)anObject didSomethingElse:(id)anotherObject method that calls some properties on the delegator and is much more involved.
Finally, this method allows you to use the same delegate for multiple delegators, since you don't need to update a delegator property for each delegate object.
For a good example of how this works, take a look at the NSURLConnection documentation, specifically its delegate methods - a lot of them take the form connection:didDoSomething:, where the first argument is the connection calling the delegator. Developers commonly define a single connection delegate for multiple connections, implementing their delegate methods to do different things depending on properties of the NSURLConnection object passed in.
When writing Cocoa and implementing a class method that accepts a delegate and one or more selectors to use for its callbacks, does the terminology change from "delegate" and "selectors" to "target" and "action"? More to the point, is "delegate" limited only to when my class is the one getting called, but not when my class is doing the calling?
Delegates are usually implemented using Protocols instead of selectors. This is a more formal way of communicating across classes, and is mostly useful when there is more than one method that may be needed.
Target/Action are generally used to correspond to an "event-like" situation, such as a click, a timer firing, etc.
To elaborate on NilObject's answer, delegates are implemented via protocols with a series of 'standardized' methods. If you have multiple objects each of the same class sharing the same delegate you will be unable to distinguish between the sender. Hence you see -(void)delegateCallback:(id)sender the pointer of sender allows you to make this association.
In order to make this comparison a reference to sender will be required as a property or global variable, this also makes it easier if you are manually releasing your object as you can set the objects properties to nil before releasing (to prevent garbage pointers).
Alternatively you can use the selector method to pass in your own method for callback, this technique is good as you don't require the reference for a comparison with the :(id)sender and you can have a method callback for each object you initialize. On the flip side the lack of reference means that if you release this object you will be unable to set the properties to nil.
I think there is a difference at design level.
Let's take a component which is specialised to do some stuff. Both Delegation and targetAction would facilitate (some form of) communication between our component and the object that consumes it.
Usually, which form of communication is desired defines whether to use Target Action or Delegation.
1. What is getting communicated?
Target Action is more suitable when the communication is limited to control (events, state, etc)
Delegation is much more flexible and has wide applications. So I can use delegation to send and receive data between 2 objects.
2. How
So far I've seen Target Action to mostly manifest 1-Way communication
With Delegation I've myself done 2-Way communication by having methods that return values.
Target - the object which is going to respond for your action.
Action - the method which is triggered by your action
Delegates - Majorly used for callback mechanism, implemented using "#protocols".
Selector - also can be used as callback method:
Eg:
SEL mySelector = #selector(myTimerCallback:);
[NSTimer scheduledTimerWithTimeInterval:30.0 target:obj selector:mySelector userInfo:nil repeats:YES];