You guys might remember my post from a few weeks back asking for tips on iPhone dev. Most replies pointed back to Apple's developer site and the SDK, and those sources have been very helpful. I've been immersed in it for a couple of weeks now and everything is going well. I got over the Objective-C hurdle, though I can't say I like it. I'm constantly amazed that 250k apps got written in it. Either there were a lot more people out there with C in their backgrounds than I thought, or there are a lot of broken, crappy apps.
Cocoa, on the other hand, is giving me some trouble, and I decided to post in the hope that someone here who has grok'd all this will be able to guide me through the fog. My question could probably best be summed up as: when do I need a UI object, and when do I need both a UI object and a controller?
For example, I have a detail edit dialog that needs to pop a UIPickerView so the user can pick from a list. The dialog itself consists of a class derived from UITableViewController, that creates a default table view internally, which is then populated with data by the controller class. So there you have a UI "component" that is essentially a controller tightly integrated with a contained view. Integrated in this case means "implements UITableViewDelegate and UITableViewDataSource protocols," which for those of you non-obj-c types who might be reading this means: implements some defined methods and passes a self pointer to an object that will call back into those methods. In this case the UITableView will call back into my derived controller.
This tight coupling between controller and view classes confuses me. I can't quite figure out who I am supposed to be dealing with. If I pop the view by pushing the controller onto a navigation controller then I am clearly dealing with the controller class. If I add the controller.view property as a subview of a window I'm dealing with the view itself. Both get the thing displayed on screen and interacting. To make it more confusing, let's return to my UIPickerView requirement.
I need to display a picker in my dialog. I can just create a UIPickerView, and implement its protocol methods, then add it to my view as a subview. If I do that then I guess the dialog controller is also acting as the picker controller. Alternatively I can derive from UIPickerViewController and create a controller class, that internally creates a UIPickerView. The controller class can implement the protocol methods, and configure the UIPickerView according to property values, or whatever. The controller can also hold a reference to the data source. In a sense the controller "encapsulates" the picker view, and in fact it is a containment relationship. So is the controller supposed to become a proxy for the view? What if the view has a dozen properties like background, alpha, size, etc., and clients need to be able to configure those? Do you reflect those properties onto the controller? Do you use the controller.view and go configure the view directly?
I am having a hard time figuring out what the "right" pattern is. I mean, it's clearly a matter of degree to some extent. UIViews composed of other UIViews don't interact with a controller class for every element. Essentially the protocols for the contained child controls are folded into the hosting view's controller.
I guess I don't really understand this architecture. It's obviously supposed to be MVC, but these "controllers" are very tightly coupled to the UI elements they are controlling. In an activity overlay dialog that I made yesterday I have a UIView and a UIViewController. The controller actually has a loadview callback in which it creates the main view and all the subviews needed. That's typical of the examples I've seen. So the controller knows a hell of a lot about the internals of the view, and in that case I also reflected key view properties like alpha out to the controller interface. Just didn't feel right or elegant.
Cocoa, on the other hand, is giving me some trouble, and I decided to post in the hope that someone here who has grok'd all this will be able to guide me through the fog. My question could probably best be summed up as: when do I need a UI object, and when do I need both a UI object and a controller?
For example, I have a detail edit dialog that needs to pop a UIPickerView so the user can pick from a list. The dialog itself consists of a class derived from UITableViewController, that creates a default table view internally, which is then populated with data by the controller class. So there you have a UI "component" that is essentially a controller tightly integrated with a contained view. Integrated in this case means "implements UITableViewDelegate and UITableViewDataSource protocols," which for those of you non-obj-c types who might be reading this means: implements some defined methods and passes a self pointer to an object that will call back into those methods. In this case the UITableView will call back into my derived controller.
This tight coupling between controller and view classes confuses me. I can't quite figure out who I am supposed to be dealing with. If I pop the view by pushing the controller onto a navigation controller then I am clearly dealing with the controller class. If I add the controller.view property as a subview of a window I'm dealing with the view itself. Both get the thing displayed on screen and interacting. To make it more confusing, let's return to my UIPickerView requirement.
I need to display a picker in my dialog. I can just create a UIPickerView, and implement its protocol methods, then add it to my view as a subview. If I do that then I guess the dialog controller is also acting as the picker controller. Alternatively I can derive from UIPickerViewController and create a controller class, that internally creates a UIPickerView. The controller class can implement the protocol methods, and configure the UIPickerView according to property values, or whatever. The controller can also hold a reference to the data source. In a sense the controller "encapsulates" the picker view, and in fact it is a containment relationship. So is the controller supposed to become a proxy for the view? What if the view has a dozen properties like background, alpha, size, etc., and clients need to be able to configure those? Do you reflect those properties onto the controller? Do you use the controller.view and go configure the view directly?
I am having a hard time figuring out what the "right" pattern is. I mean, it's clearly a matter of degree to some extent. UIViews composed of other UIViews don't interact with a controller class for every element. Essentially the protocols for the contained child controls are folded into the hosting view's controller.
I guess I don't really understand this architecture. It's obviously supposed to be MVC, but these "controllers" are very tightly coupled to the UI elements they are controlling. In an activity overlay dialog that I made yesterday I have a UIView and a UIViewController. The controller actually has a loadview callback in which it creates the main view and all the subviews needed. That's typical of the examples I've seen. So the controller knows a hell of a lot about the internals of the view, and in that case I also reflected key view properties like alpha out to the controller interface. Just didn't feel right or elegant.