I could use some architectural advice. I've run into the following problem a few times now and I've never found a truly elegant way to solve it.
The issue, described at the highest level possible:I have a parent class that would like to act as the delegate for multiple children (all using the same protocol), but when the children call methods on the parent, the parent no longer knows which child is making the call.
I would like to use loose coupling (delegates/protocols or notifications) rather than direct calls. I don't need multiple handlers, so notifications seem like they might be overkill.
To illustrate the problem, let me try a super-simplified example:
I start with a parent view controller (and corresponding view). I create three child views and insert each of them into the parent view. I would like the parent view controller to be notified whenever the user touches one of the children. There are a few options to notify the parent:
Define a protocol. The parent implements the protocol and sets itself as the delegate to each of the children. When the user touches a child view, its view controller calls its delegate (the parent). In this case, the parent is notified that a view is touched, but it doesn't know which one. Not good enough.
Same as #1, but define the methods in the protocol to also pass some sort of identifier. When the child tells its delegate that it was touched, it also passes a pointer to itself. This way, the parent know exactly which view was touched. It just seems really strange for an object to pass a reference of itself.
Use NSNotifications. The parent defines a separate method for each of the three children and then subscribes to the "viewWasTouched" notification for each of the three children as the notification sender. The children don't need to attach themselves to the user dictionary, but they do need to send the notification with a pointer to themselves as the scope.
Same as #4, but rather than using separate methods, the parent could just use one with a switch case or other branching along with the notification's sender to determine which path to take.
Create multiple man-in-the-middle classes that act as the delegates to the child views and then call methods on the parent either with a pointer to the child or with some other differentiating factor. This approach doesn't seem scalable.
Are any of these approaches considered best practice? I can't say for sure, but it feels like I'm missing something more obvious/elegant.
Your #2 is the standard Cocoa pattern for delegates. Each message of the delegate protocol takes the object as the first argument. For example, in UITableViewDelegate, you find methods like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
When a table view sends this message to its delegate, it sends itself (the table view) as the first argument. If the delegate object is the delegate of multiple table views, it can use the first argument to figure out which table view sent the message.
When there are no other arguments, the message still takes the object as an argument, as in this UITableViewDataSource method:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
You will find this pattern all over the Cocoa Touch framework; UIPickerViewDelegate, UIImagePickerControllerDelegate, and UINavigationControllerDelegate are just a few examples.
You should follow the standard pattern unless you have a compelling reason not to. Following the convention will make it easier for others (and future you) to understand your code.
Related
I have just a minor question about coding style.
I have a subclass of UIViewController which is a delegate to an MKMapView object. Naturally, I have an ivar in my view controller which points to said MKMapView. When I'm writing one of the callback methods mapView:didUpdateUserLocation:, is it smarter to send messages to the passed-in reference of the map view or to the ivar reference of the map view?
I'm aware these are essentially the same thing. I use the ivar reference of the map view object. What are the pros and cons of both styles?
Since you know that both MKMapView objects are one and the same thing, it doesn't matter in this particular case. The reason for the convention requiring the first delegate parameter to be the calling object is to handle the situation when a class is a delegate to more than one object. E.g. if you show two different UIAlertView's in your view controller, and the view controller is a delegate to both (a common scenario), then you want to know in the delegate methods which alert view you're dealing with.
I have two childViewControllers of the same parent, say methodChild and propertyChild, and want a method in methodChild to be called every time a new value is set in one of propertyChild's properties. What is a good way to do this?
One solution that occurred to me was this:
In the property setter, find the other child (perhaps through the parentViewController method and childViewControllers array) and ask it to perform the method.
My main worry with this sort of thing is accidentally creating a retain cycle or a memory leak of some sort, so any advice on this would be terrific. Thanks for reading!
The parent can hold references and keep track of the data that changes. It can simply call exposed update methods of its children.
The child controllers should use delegate protocols to inform the parent of changes. The delegate is weak reference to the parent in the form id <ChildDelegate>. This is to avoid the retain cycle problems you are afraid of.
I just created a custom UIViewController with some user actions like touch. I would like to handle the user interaction in the parentObject. In other words the one that created the ViewController.
From other languages I am used to use Events that are pushed up. So my parent object would have some kind of listener on the reference of the ViewController object it can react to.
How would that type of interaction handled by Objective C?
This can be done by 1) responder chain, 2) notifications and 3) delegates.
All UI objects form the responder chain, starting from the currently focused element, then it's parent view and so on, usually until the application object. By sending action to the special First Responder object in your nib, you'll throw it down the responder chain until someone handles it. You can use this mechanism for firing events without knowing who and when will handle them. This is similar to HTML event model.
Notifications send by NSNotificationCenter can be received by any number of listeners. This is the closest analog to e.g. C# events.
Delegates is the simplest mechanism of sending event to one single object. The class declares weak property named delegate that can be assigned with any object, and a protocol that this object is supposed to implement. Many classes use this approach; the main problem is that you can't have more than one listener this way.
you should look into delegations/delegate for interactions between two viewControllers. You need to understand how it works first.
https://developer.apple.com/library/mac/#documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html
It sounds like you need to implement a delegate protocol, which will allow your 'child' view controller to communicate back to it's 'parent'
See http://developer.apple.com/library/ios/#documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html
As many other developers new to Cocoa, I struggle with delegate and controller concept. I get the basics, but one thing bugs me. Practically every explanation says that "usually" or "in simple cases" (which are the only ones they give as examples) controller and delegate tend to be the same object.
That leads to a question: when would you want to separate controller and delegate for the same interface object?
Two general cases when using a separate class for your delegate is needed are
When you need to perform unrelated actions in response to the same delegate message, or
When you would like to share the logic of the delegate among multiple views or controllers.
An example of the first situation would be a page with two unrelated tables. Each UITableView would need its own delegate, so using the controller as the delegate would require an ugly if statement in each delegate method; defining and using separate delegates is clearly preferred in this case.
An example of the second situation would be a group of similar pages that show DB data from tables of similar structure. Pages themselves are sufficiently dissimilar, so you cannot reuse the controller in its entirety. If you choose to put the delegate into the controller, most of the logic behind the table view's data source would be identical. You can put the code into a shared delegate implementation, and have each controller instantiate that delegate with the configuration parameters specific to the table associated with this controller.
One note to keep in mind when using another object besides the controller as your delegate: the controller should retain / keep a strong reference to the delegate, since the view will only keep a weak / assign reference to it. See property "assign" and "retain" for delegate for more information on this.
Hey guys, I currently have a root table view which has a toolbar at the bottom and has labels and a refresh button within it, much like the Mail app's toolbar. This root table view controller obtains data from a server by allocating and initializing a DataUpdater class. Within this class are the NSURLConnection delegate methods that are called while communicating with the server.
As you can probably guess, I need to know when certain (delegate) functions are called within the DataUpdater class and the values of the parameters passed to these delegate functions so that I can update the labels on the toolbar accordingly (i.e. Connecting..., Updated, etc).
The problem I am having is determining how to notify the root table view controller of what is going on in these delegate methods. Would I use protocols, if so how? I have been skimming the documentation and don't quite see how I would get this effect. Or would you suggest I implement my program another way?
Thanks in advance!
A protocol is a kind of contract that says: I promise to provide the non-optional methods defined in the protocol, and maybe even the optional ones. It's purpose is like Java interfaces: to work around missing multiple-inheritence.
The delegate pattern in Objective-C normally works like this: you define a protocol, and then in your class, you define a variable like id<MyProtocol> myDelegate; and define a setter and maybe getter (either via normal methods, e.g. - (void)setDelegate:(id<MyProtocol>)aDelegate; or via properties.
Note that the delegate is not retained ! So if you work with a property, you need the assign option, not retain.
Now back in your class, you check whether myDelegate is nil and if not, you can directly call its non-optional methods. If you want to call an optional method, you first need to verify its presence via respondsToSelector:.
So if you decide to use the delegate pattern, you need to define a protocol, add that protocol to your root table view controller, implement the necessary methods there, and make sure to call [foo setDelegate:self]; or something similar to inform your other class that the root table view controller is the delegate. And of course implement the delegate calls in your class.
Edit:
An alternative might be to use NSNotifications, BTW. The advantage of notifications is that you can have multiple objects listen and react to them. The disadvantage is that you cannot (directly) pass values back. For example, you can define a delegate method that asks the delegate whether to do something or not. That's not possible with notifications, it's more like shouting into a room instead of having a one-to-one conversation.
DarkDust's answer about protocols is fine but I would like to add some things to it.
One underlying thing that is often forgotten when it comes to delegation is object ownership. When a program is running it creates a tree of objects. Its root object is the application delegate and for example it owns a navigation controller, which owns the individual view controllers, which own the view and the view owns its subviews and so on.
Often the question comes up: "Why is the delegate not retained, just assigned?" The problem is that if you send a message to a deallocated object the program crashes. So how do you make sure the delegate stays around? The answer is object ownership.
I give you an example: a UITableView and its data source which is the TableViewController which is nothing but a delegate. The TableViewController holds a reference with its view property to the UITableView, so it owns the TableView. That means when the tableView is alive there must also be its parent object present, which is the UITableView's delegate. So there is no danger that the delegate goes away somehow.
In the end it is again all about memory management.
Take home message is: think upfront about object ownership will make your program mode modular, easier to maintain and will lead to a looser coupling between individual objects.