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];
Related
Cocoa uses delegates extensively to provide (among other things) callback methods for asynchronous operations. However, I personally hate the delegate model and how it pollutes the current class with handlers for very specific child operations. UIAlertView is a perfect example.
Therefore, I'm wondering if it's possible to simply create an anonymous delegate object that meets the requirements of a delegate protocol (such as UIAlertViewDelegate) via blocks and pass this anonymous object wherever a delegate reference is expected.
I imagine something like so:
id myDelegate = #{
alertView:alertView didDismissWithButtonIndex:index = ^ {
...
}
};
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:... message:... delegate:myDelegate cancelButtonTitle:... otherButtonTitles:...;
[alertView show];
I've heard Objective-C has some good dynamic language features but I don't know how to simply add a method/selector to an object. Can this be done in a relatively straightforward manner?
Yes, the language features you mention are exposed via the objective-c runtime, although there's no built-in facility to dynamically create delegate classes and the runtime api is not the friendliest of things.
There is a library called A2DynamicDelegate, which does exactly what you're talking about. I haven't used it, but it may be worth investigating.
EDIT: A problem with this approach is that delegates are not retained, so you'll need to either keep a strong reference somewhere else, or an add an associative reference to the UIAlertView. You may find that all this fuss isn't worth it and just adding an extra method to your view controller works better (you can conform to the delegate protocol in a class extension to avoid polluting your interface).
One option is to write a class which wraps your blocks for the individual methods of the delegate protocol into a delegate object. For details see this answer.
You should consider using a category that adds block support to UIAlertView, which seems to address your use case. UIAlertView-Blocks is my favorite one although there are many others.
If you want to use blocks with a delegate-based API, you'll have to do some subclassing. For example, see PSAlertView, which subclasses UIAlertView to provide a block-based API.
I want to have multiple observers on multiple events of a single object (1-to-N relationship).
A mechanism to achieve this task is provided by the NSNotificationCenter. The mechanism looks pretty overkill when used for my problem.
How I would do it manually without the use of NSNotificationCenter:
- (void)addDelegate:(id<DelegateProtocol>)delegate;
- (void)removeDelegate:(id<DelegateProtocol>)delegate;
to add and remove observers from my object.
- (void)someEventFired:(NSObject<NSCopying> *)eventData
{
for (id delegate in delegates) {
NSObject *data = [eventData copy];
[delegate someEventFired:data];
}
}
This mechanism is straight-forward and simple to implement without the objects having to share additional strings.
Is there an official pattern for 1-to-N delegates (like C# events) in an iOS framework besides the NSNotificationCenter?
When should the NSNotificationCenter be used and when not?
When should an implementation like the one I am suggesting here be used and when not?
By convention, delegates should probably only be used for 1:1 relationships. If you really need 1:N relationships for this type of functionality, you have two options:
As you mentioned, NSNotificationCenter.
Key-Value Observing (also known as KVO).
KVO is appropriate if you only care about when a particular property of an object changes. Otherwise, you should really just consider using NSNotificationCenter. You can even be notified only when a specific object posts that notification by passing that object into the addObserver:selector:name:object: method.
Apple uses NSNotification in similar scenarios (like the notifications defined for UITextField, including UITextFieldTextDidBeginEditingNotification, UITextFieldTextDidChangeNotification, and UITextFieldTextDidEndEditingNotification).
using notifications is broadcasting: 1 sender just sends an information and who ever tuned in, receives it. Petty much like a radio station, there is no channel back (lets for the moment forget about telephones)
delegation is something different. Th object, that asks a deleagte to do something, usually needs a result of that request, there fore delegation is a 1-to-1 communication, that is always initiated by the object, not the delegate (while the object can have methods that can be called to inform the object to initiate the communication, ie [tableView reloadData]).
So if the sender needs to get data back, it is delegation. If the sender doesn't care about anything after broadcasting, go with notifications.
If you run into the situation, that you need delegation, but several objects should implement the protocol. you should have 1 delegate, that hold references to the other objects and calls the methods on the senders behalf — or you could go with blocks.
NSNotificationCenter is not overkill for what you are suggesting, it is exactly the right solution. It prevents the observed object having to know or care about its observers, making your code more loosely coupled and cleaner.
Sharing strings for notification names is trivial and they can be defined in either a shared constants file or in the header of the observed object, if your observers need to import this header to do their jobs.
Your proposed solution is neither simpler than using NSNotificationCenter nor is it thread safe.
To make your solution thread safe, you would need to provide a mechanism to prevent the delegates array from changing while the event dispatch for loop is running.
Your solution also requires that you maintain the delegates array in your class. With the NotificationCenter you can simply use the default center and you don't need to implement the add/remove methods in your class. Instead, instances can register themselves to receive notifications as they see best fit (selector/block, queue, source). Your source class doesn't have to worry about those details. It only needs to register itself as a source of notifications of a specified type. Using blocks to handle notifications is really convenient.
An alternative to the notification center is to use Key-Value-Observing if that meets the needs of your use case.
Ultimately, the mechanism you decide to use depends on how best it applies to your specific use case.
A 1-to-N delegate relationship doesn't make sense. Have a look at
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
for example. What if this object really had n delegates? How should it decide which of the n views it gets back from all its delegates should be used? Delegates are exactly this 1-to-1 principle.
The NSNotificationCenter is the right approach. Simply use
addObserver:selector:name:object:
respectively
postNotification:
This is definitely not too much code. And it's very easy for you as the center handles all calls.
You don't want to use NSNotificationCenter for anything other than system-wide events (e.g. the appearance of the keyboard or some similar event). The reason is that it is completely not type-safe, can make everything dependent on everything and that you get no compile time checks or usage search results anymore.
KVO in my opinion should not be used to observe changes outside of the object you're listening to since it has similar down sides (no compile time checks, crashes if you don't remove listeners properly or register them twice).
The addDelegate/removeDelegate pattern that you pose is completely the right path in my opinion since that has the advantage of maintaining type-safety and compiler checks and makes dependencies explicit. The only problem is that Apple doesn't supply an out-of-the-box solution for this pattern, since you need a collection type that weakly retains its elements to avoid retain cycles.
However, see code from my BMCommons framework which solves this problem neatly using BMNullableArray and macros. See the BMCore.h header for a definition of those macros:
BM_LISTENER_METHOD_DECLARATION(protocol)
BM_LISTENER_METHOD_IMPLEMENTATION(protocol)
The implementation ensures that the same listener will never be added twice and also that listeners are weakly retained, not causing any crash even if they forget to deregister themselves upon deallocation (although I prefer to catch this condition with an assert since it is a programming mistake).
I say NSNotificationCenter should ALWAYS be used, over the delegate model, except in situations where you query a delegate on information (e.g. -webView:shouldLoadRequest:). It is more stable, easier to implement, and results in cleaner code then trying to use a delegate. The other alternative is blocks, which can be good, but they can be a pain when it comes to memory-managment.
In the end, it's up to you, but I think that NSNotificationCenter is the best way to go in almost any situation, if only for the multiple observer functionality.
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).
What is the delegates in Objective-c ?
and what is the delegates methods. ?
any one can explain with one example.. please.
tnax and regards.
As mentioned in the Apple developer documentation on Delegations:
Delegation is a simple and powerful
pattern in which one object in a
program acts on behalf of, or in
coordination with, another object. The
delegating object keeps a reference to
the other object—the delegate—and at
the appropriate time sends a message
to it. The message informs the
delegate of an event that the
delegating object is about to handle
or has just handled. The delegate may
respond to the message by updating the
appearance or state of itself or other
objects in the application, and in
some cases it can return a value that
affects how an impending event is
handled. The main value of delegation
is that it allows you to easily
customize the behavior of several
objects in one central object.
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.