iOS layout; I'm not getting it
Well, "not getting it" is too harsh; I've got it working in for what for me is a logical setup, but it does not seem to be what iOS deems logical. So I'm not getting something.
Suppose I've got an app that shows two pieces of information; a date and a table. According to the MVC approach I've got three MVC at work here, one for the date, one for the table and one that takes both these MCVs and makes it into a screen, wiring them up.
The master MVC knows how/where it wants to layout the two sub MVC's. Each detail MVC only takes care of its own childeren within the bounds that were specified by the master MVC. Something like:
- (void)loadView {
MVC* mvc1 = [[MVC1 alloc] initwithFrame:...]
[self.view addSubview:mvc1.view];
MVC* mvc2 = [[MVC2 alloc] initwithFrame:...]
[self.view addSubview:mvc2.view];
}
If the above is logical (which is it for me) then I would expect any MVC class to have a constructor "initWithFrame". But an MVC does not, only view have this.
Why?
How would one correctly layout nested MVCs? (Naturally I do not have just these two, but the detail MVCs have sub MVCs again.)
Thanks all for replying. I will study the links that were provided.
Let me try to explain my issue one more time, hopefully to making it more clear. Do note that I already figured out that my view does not match iOS's, since I do not like where my code is going.
Yes, I'm calling a UIViewController an "MVC", since it for me at the moment implements all aspects of a MVC; it has controller code and an embedded view, plus the controller usually also holds and provides the data (all TableView examples implement it like this).
MVC can be present on many levels; basically a UITextField could (should?) be a MVC; there is a view, but also controller logic involved that you do not want to mix with other code. Encapsulation. For example: Java's Swing JTextField has a MVC. So does a JTable, JList, ... Multiple MVC patterns nested in other MVC's to build a whole screen.
This what I expect when some platform says it uses the MVC pattern. So When I coded the table, I created a MVC and only send the loadData message with a date as the parameter to it. It needs to take care of the rest itself. I have a Detail MVC that can slide in; I then tell it the object it needs to show and it needs to take care of the rest itself. Encapsulation.
So I have a lot开发者_如何转开发 of UIViewControllers with embedded UIViews. And that is not the way to do it...
One more potential link is the great talk from WWDC 2010 on MVC.
http://developer.apple.com/videos/wwdc/2010/
It is Session 116 - Model-View-Controllr for iPhone OS
The session is chock full of practical advice on how MVC really works, what makes it tick, why it's good. But it also has a lot of intro stuff to help folks new to the concept to wrap their heads around it.
If I understand your sentence on Java's Swing classes above are you talking about the anonymous classes that respond to events? If so those are not "MVC's", they are what is termed 'Observers', when they observe an event from the view they take some action (usually send a message to a controller). Cocoa Touch uses the Target/Action paradigm (and delegation) to achieve this.
I'd also strongly suggest you take Matthew and Stephen's advice and write a bunch of code. If you don't build that base of intuition, asking the right question (which is most of what is needed to get a good answer) is very difficult.
I really think the WWDC 2010 talk will help.
Good Luck!
If I understand your question -- and I may not, see my comments on it -- I think you're applying the MVC design pattern far too granularly. Most commonly in the setup you describe you'll have a single Model, a single Controller, and multiple Views that are grouped/combined, as in a .xib
file.
In Cocoa Touch terms you'd have one UIView that contains a UILabel with the date and a UITableView for your table. These are your Views.
You'll certainly have a Model for the table data, likely an array of data. Your date data might be from its own model if it's a date retrieved from something or calculated or whatever, something entirely separate from the array of data. If it's instead associated with the array data -- they're both pulling from a database, or the date is calculated from the array data, or what have you -- then you have a single Model.
If the data is all coming from a single Model then a single Controller is likely fine. Even if the data is coming from more than one source/Model you likely only need/want one controller in this setup. The UITableView will have a UITableViewController, and that same controller can take care of providing your date as well.
To sum, the Model View Controller design pattern doesn't call for having a bunch of nested sets of models, views, and controllers. They could be, and sufficiently complex projects may call for it. Broadly, though, you'll have a controller that's associated with a model and one or more views, and that set of objects works together to provide a piece of functionality.
Tbee,
I'll post a tiny code example here, since it seems you're not really getting it.
@interface MyView : UIView
@property (retain) IBOutlet UIButton *button1;
@property (retain) IBOutlet UIButton *button2;
@property (assign) bool myData;
-(IBAction) doButton1:(id)sender;
-(IBAction) doButton2:(id)sender;
@end;
@implementation MyView
@synthesize button1 = _button1;
@synthesize button2 = _button2;
@synthesize myData = _myData;
// I'm leaving out the initWithNib, viewDidLoad, etc.
- (IBAction) doButton1:(id)sender
{
// do something as a result of clicking button1
_myData = YES;
}
- (IBAction) doButton2:(id)sender
{
// do something as a result of clicking button2
_myData = NO;
}
@end
Connect those up in InterfaceBuilder, and you've got a working "MVC." You don't need a completely new UIViewController for each button. The one for the View takes care of it.
UITableView
and it's associated Views are more complex, and may require an additional UIViewController to help encapsulate. I really don't suggest starting out by using them, but this is a good tutorial here. It's got a lot of images which will show you how to connect things up in IB and the like. It's old, so your XCode may not look like the images, but it helps.
Thanks for the links, I'll look into them.
So far I've rewritten most of my application to using views instead of viewcontrollers (except the toplevel one) and it starts to match up with the API calls that are available like layoutSubviews. What I find disturbing that I need to do this now:
[tableDataSource loadData:date];
[tableView reloadData];
Where in my previous setup all I did was:
[tableViewController loadData:date];
But apparently that is the way to do it. One thing is unclear to me ATM. Since I construct and layout the view in loadView in my AppViewController, how do they get relayouted if the orientation changes. The VC does not have a layoutSubviews, so I should use the didRotateFromInterfaceOrientation and reposition the subviews from there?
BTW, I'm not mixing registering anonymous inner classes as listeners (observers). I'm very experienced with writing Swing components and JavaFX controls. And that probably is the culprit, in Java(FX) every component has a view and a controller (not always a model).
精彩评论