Delegation coding style? - objective-c

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.

Related

IOS: is it possible to bind one story board view controller to several different classes?

I know it's possible to attach a custom view controller class to several different view controllers on a storyboard, but can it be done in the other direction; that is, depending on the situation, I want to bind different custom classes to a single view controller on the storyboard that will be instantiated using:
[self.storyboard instantiateViewControllerWithIdentifier:]
background: I used to have several view controllers on my storyboard that are almost identical. In fact, the custom classes that they each bind to are very similar as well. In an effort to clean this up, I refactored my custom classes into one base class and several subclasses. I then removed all the similar view controllers from the storyboard leaving only one which I've bounded to my base class. I then call:
MySubclass* mySubclass = [self.storyboard instantiateViewControllerWithIdentifier:#"StoryboardControllerBoundToBaseClass"];
Unfortunately, my subclass code is being ignored and only the base class code is ever run. Does anyone know how I can make it work without duplicating view controllers on the storyboard and binding each one to a different subclass?
It's not possible. Just because you say MySubclass *object = something doesn't magically convert object into a MySubclass object. It's stored in the storyboard with whatever class was assigned at storyboard compile time.
Rather than using subclassing, I figure I can reuse a view controller on the storyboard by using a delegate/proxy model. More specifically, I can bind the storyboard's view controller to a custom class that delegates all of its methods/events to others classes to handle. This isn't as elegant as subclassing but at least I can keep my storyboard leaner, not having to keep several copies of pretty much the same view controller. Plus, I won't need to duplicate future changes to every copy of these controllers to boot.
As guylegend writes. Apple doesn't support the way to do that. There are many workarounds e.g. with delegates but I finally found the answer and answered in another topic. Hope it helps!
https://stackoverflow.com/a/32103618/1943053

Call method in UITableViewController from custom UITableViewCell

I need to call a method and pass an object from my custom UITableViewClass implementation to my UITableViewController class. I realize creating an instance of the tableViewController in the custom tableViewCell and calling tableViewController's method is a bad practice.
What is the proper way of doing this?
Two magical concepts in Objective-C are Delegation and Notifications.
Delegation allows you to have your controller hook into a weak object referenced in the cell, which avoids a retain cycle, while still allowing you to send messages to it.
Notifications allow your Cell to broadcast a general notification to any classes that are active and listening for it.
Pick one, and whichever is easiest, stick with it. The two are basically equal in this situation.
Having a reference of the tableController inside the cell is indeed Bad practice
You could fix this by implementing a special #protocol for your UITableViewClass
And add a delegate method to it, and then implment the method inside UITableViewController, and since your UITableViewClass delegate is your UITableViewController, then you would call it like
in your UITableViewClass.m
[delegate someMethod:data];

Separate Delegate and Controller

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.

Using Protocols in Objective C to Transfer Data Between Different Objects?

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.

Drag-and-drop files onto an NSTableView?

I have an NSTableView which I wish to allow users to drag-and-drop video files onto. When they drop the file, it'll get added as a row in the table view.
How would I go about doing this? Currently the tableview's takes its data from an Array Controller (which takes its data from a NSMutableArray)
I found this documentation, but cannot seem to make it work..
I have..
made a "TableCon" class (which I changed to inherit from NSTableView, not NSObject)
changed the NSTableView class to TableCon
set the NSTableView's delegate outlet to that class
called registerForDraggedTypes in TableCon's init
implemented - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender; (again in TableCon)
..but, nothing, it acts like I never changed anything (no errors), what am I doing wrong?
Edit: I've tried implementing Boaz Stuller's suggestion, and also found this description of the solution (the first reply includes the solution to the first post). So what I have done now is..
Subclass NSArrayController which feeds content to the table view (TableListCon)
Add tableView outlet to TableListCon (and pointed it at the NSTableView)
Implement validateDrop, writeRowsWithIndexes, and acceptDrop in TableListCon
Called registerForDraggedTypes on the tableView outlet.
Again, no errors/warnings, but only the awakeFromNib method seems to be called (None of the other methods are called)
NSTableView handles drag-and-drop differently from generic views, which is overall a good thing. It means that you don't have to manually handle the complicated highlighting, cell tracking and inserting behaviours that tables require.
A description of what is required can be found here. Basically, you still call -registerDraggedTypes: (generally in your -awakeFromNib method) but instead of implementing the NSDraggingDestination methods, you implement the various data source methods associated with drag and drop, which can be found here. You should not need to subclass NSTableView to implement drag-and-drop in this fashion.
Note those are data source methods. You need to hook the table view's dataSource outlet to the class that implements those methods in order for them to be called.
In addition to what Boaz said, it sounds like you're creating an NSTableView subclass and then making an instance of that subclass the delegate of NSTableView. If you're going to subclass, that subclass should be used in place of NSTableView, not in addition to it. Also, it's almost always a violation of concerns to have a view be a delegate for another object.