I am currently working with Swift and I was learning about MVC - one question that popped out was this: I am trying to implement a WKWebView - and I already know how to do this within a ViewController.
My question is: should I create my own WebView class to place the WKWebView or should I only house it with in the ViewController? I am trying to follow the MVC structure.
It's a web view, so it should be placed in the view controller in the storyboard. This really has nothing to do with MVC, per se.
The view controller is your Controller.
The view controller's root view and the web view you're putting in it are the View.
The Model may or may not be relevant here since a model is usually just a data structure that the Controller uses to populate the View. It could just be the HTML that you pass to the web view.
My question is: should I create my own WebView class to place the WKWebView or should I only house it within the ViewController? I am trying to follow the MVC structure.
The view in Model View Controller really refers to a view and its entire graph of subviews. If a WKWebView instance is the view that contains everything that the controller will manage, then it's fine to make that "the" view; there's no need to put it inside another view just for the sake of containing it. On the other hand, if you want the same controller to manage other views not contained in the web view, then you can put the web view and the others all inside some other view and let the controller manage that.
How you organize your views really isn't determined by MVC -- just do what works. MVC really speaks to the way that the information your app operates on is owned and managed by a model, displayed in a view, and how the interactions between model and view are mediated by the controller.
Related
This question already has answers here:
What is the difference between a View and a View Controller? [closed]
(3 answers)
Closed 7 years ago.
Coming to Swift from Delphi, I thought the View represented an app's GUI and the storyboard was a visual representation of the View's underlying code. The ViewController was the one and only object the View interacted with. When a popular tutorial says
In the old days developers used to create a separate interface file
for the design of each view controller.
I'm thinking the "separate interface file" was the View file. But as I learn more, I'm getting confused. Beneath a screenshot of an empty Main.storyboard from a new application, the text says
The official storyboard terminology for a view controller is "scene,"
but you can use the terms interchangeably. The scene is what
represents a view controller in the storyboard ... Here you see a
single view controller containing an empty view.
So I'm seeing a "single view controller," not a view?? Confusion mounts when I note any views(?) displayed on a storyboard are called "View Controllers" in Swift.
So, what's the difference between a View and ViewController? How is a storyboard related? And what object "owns" something like a segue, which exists outside my (flawed) understanding of these concepts?
Take a look at this post - What is the difference between a View and a View Controller?
This described it pretty well for me.
If you don't want to go to the link, here is a great description of the difference between a view and a view controller by Alex Wayne:
A view is an object that is drawn to the screen. It may also contain
other views (subviews) that are inside it and move with it. Views can
get touch events and change their visual state in response. Views are
dumb, and do not know about the structure of your application, and are
simply told to display themselves in some state.
A view controller is not drawable to the screen directly, it manages a
group of view objects. View controllers usually have a single view
with many subviews. The view controller manages the state of these
views. A view controller is smart, and has knowledge of your
application's inner workings. It tells the dumb view objects what to
do and how to show themselves.
A view controller is the glue between your overall application and the
screen. It controls the views that it owns according to the logic of
your application.
I'm bit of a newbie and had a basic question regarding adhering to the MVC model in iPhone coding.
How do I setup a Model class that holds my data and connect it to different controllers in the following setup:
Using Interface Builder, I created a tab controller in which
- Tab #1 has a Nav Controller and a hierarchy of View Controllers.
- Tab #2 has a View Controller
So with what I have now, the View Controller under Tab #1 alloc init's the model class and I know how to pass the model from one ViewController to the next in the Navigation Hierarchy where it can pass the data and/or be updated with new data.
Question is how to pass it from Tab #1's View Controller to Tab #2 View Controller as there is no code linking the two???
Thanks in advance,
Hiren.
It really depends on your application's needs. There are a number of approaches. For what you've described, I'd probably (a) add a Model to your root view controller, then add/update the various view controllers when they're selected (a delegate here would be useful, too) or (b) create a Singleton for your data model.
I would suggest having the model owned by the application delegate. The controllers can get the delegate using [[UIApplication sharedApplication] delegate] and load data using properties or methods.
I'm diving into iOS development and am getting familiar with navigation view controllers. I'm trying to build a simple app with a table view that allows me to add objects to it. So far, I have a table view with an add "+" button in the nav bar that allows me to load my CreateObjectView and display it modally so the user can define the new object, but when they click the save button, I don't know how to send that object data back to the parent view that created the CreateObjectView that contains the object data.
When I create the child view (CreateObjectView), I could pass into it a pointer to the current view before I push it onto the nav stack, but this just feels dirty and circular.
I was reading about protocols and delegates and I could use that approach as well, but it also feels circular.
This question seems like it would be a common design issue to any tableview-based or nav-based app, how should I probably access the view that is one level up from my current view in a nav-based iOS app?
Thanks so much in advance for all your help!
It feels circular at first, but it is the right way. Before the UINavigationController pushes the new view controller you should set the delegate to the current view controller - assuming that's the object you wish to communicate with. Of course you could set it somewhere else instead, such as to a central Core Data handler. Then when you need to communicate call the delegate with the method you have defined. I've done several navigation apps like this after seeing Apple's cookbook example, and it really works well.
I'm tinkering with an iPad app that (like many iPad apps) doesn't use the UINavigation root view control system, so I don't have natural ownership for each app "view". I essentially have two basic views: a document list view, and a document edit view.
I'm playing with UIView animation for getting from a selected document to the edit view.
I also have a toolbar on top that exists (with different buttons) in both "views".
Because I don't have UINavigation running the show for me, I have a tendency to just throw more and more stuff into one NIB and one view controller that owns the whole container. But now I'm trying to figure out how to segue from the document list view to the edit view if the edit view lives inside a different NIB, preserving the toolbar too.
Anyone have thoughts or experience on app structures like this? I find the docs lacking on best practices around code/UI structure for anything except trivial one-screen apps or full-on navigation apps.
You're not "supposed" to have parent/child view controllers owning subcomponents of the same "screen" according to the docs, but this implies one massive honking view controller that basically contains the whole app, and that can't be right.
Not sure if there's a "right answer" to this; I'm looking for some intelligent examples or suggestions. Nobody's touched this question in months, so I'm adding a bounty to generate good chatter. :)
Thanks!
UPDATE: I'm not talking about a split view, which is clearly well handled by a split view controller. Instead, take a look at Apple's iWork apps (e.g. Pages) which have a document list view and an independent edit view, but these are related by animation.
Maybe the real question here is: how would you (or could you even?) build a "container" view controller like the split view or navigation controller, yourself? Are you required to build the whole damn thing from scratch? I sense that you are, because seems to be hidden wiring in the interaction between view controllers. If so, thoughts on this?
I think the only hidden wiring in view controllers is setting parentViewController, which is required to support the categories declared for split and navigation.
View controllers are designed to be nested, with each controller owning a part of the view hierarchy. The only design goal is that no view controller reach into the view hierarchy of another controller. A parent view controller will usually have some call for adding child controllers so that it can set the frame of the view within the view hierarchy it owns. A child view controller should not do anything to the superview of the view it controls, as that is owned by another controller. Not should it set the center or frame of the view it controls.
For example, a navigation controller has a push method, in which it removes the previous controller view, adds the new controller view, and sets the frame of the newly added view. In general, a parent view controller is free to set the frame of the view of a child controller, but not the bounds.
If you want to change the animation of a navigation controller, I think you would start by implementing every method with an animated: argument. Set up your animation then call super with the animated flag off before committing the animation.
I haven't tried the multiple-view-controllers thing outside of the UIKit-provided ones (navigation/tab-bar/modal/etc) but I don't see why it shouldn't work. Under the hood, everything is a view, though I'll note that UIKit has special views for view controllers which no doubt have some kind of special handling by the system (UIViewController has a wrapper view, UINavigationController has a UINavigationTransitionView or something, ...).
I'd advise not worrying too much about "best practice" — just code something which does what you want. A couple of options:
Stick logic into view classes (ewwww!). One of our apps does this so it can handle rotation in a custom way (views slide in/out instead of rotating). We should've probably implemented our own view controller logic instead.
Break the model into components which correspond to views. Make each view know how to load its component and recursively load subcomponents. Then the view controller only needs to worry about "big picture" stuff.
Also note that you can load multiple nibs into the same view controller by e.g. connecting it to an outlet called editView.The big difference is that it's not done automatically by -[UIViewController loadView] so you need to do something like
-(EditView*)editView {
if (!editView) {
// Loads EditView into the outlet editView
[NSBundle loadNibNamed:#"EditView" owner:self];
}
return editView;
}
You'll also need to worry about adding it to your view hierarchy, unloading it on -(void)viewDidUnload (iPhone OS 3.0+), setting it up in -(void)viewDidLoad in case there was a memory warning during editing mode, etc...
It's not easy, but UI never is.
You need a master-detail view implemented with a split-view/popover-view and controlled with a UISplitViewController.
The master view is the document list and the detail view is the edit view. Each has its own controller. The two controllers themselves are managed by the UISplitViewController.
If you don't use the splitview controller you will just end up hand coding something that works very much like it. This is really the only way to do what you want easily in the API and it is the layout that iPad users will expect.
See Creating a Split View Interface in the iPad programming guide for details.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have just started developing iPhone applications and I am very confused by how the "view controller" aspect of the user interface works.
I did the "Your First iPhone Application" tutorial on the Dev Center. It has you set up your own view controller class and then initialize it using initWithNibName. So it seems that nib files contain view controllers. But it's also possible to have a nib file that just has a view, not a view controller. For example if you set up a TabBarController and then navigate to any tab other than the first one, there will be a gray box that says "view" and if you double click that you get to set up a view to go in that tab (but it's just a view, not a view controller, am I right?) So are views subclasses of view controllers or vice versa?
Another thing I am having trouble understanding is nested view controllers. The way I understand that you use a view controller (at least from the tutorial) is that you create your own custom view controller (or is it actually a view controller? In the tutorial I don't see where myViewController is actually declared to extend UIViewController) that has all the delegate methods in it, and then use initWithNibName to load the existing view controller into the custom view controller. (Right so far?) So suppose I create a nib file with a TabBarController at the root, and of course each tab will have a root view controller. So then I loadWithNibName the file and stick it in my own root view controller. Now how do I get access to all the "internal" view controllers so that I can assign delegate methods to them? Or is the recommended option to make the root view controller the delegate for both its own view and the views of all the subsidiary view controllers?
Here's another example. I am planning to have a TabBarController where for some of the tabs, the view controller for that tab will be a NavigationController. The way I understand navigation controllers is that you have to programmatically push a view on top of the stack when you want to drill down in the hierarchy. Suppose the view I pushed on is a view I originally created in Interface Builder (and loaded in using initWithNibName.) But of course the space to display the view is smaller than the space available for the view when I created it (because when I created it it was on a blank slate, while when I display it there's a navigation bar and a tab bar using up some of the screen.) So do the view controllers automatically resize the view to compensate? (IIRC, part of the documentation did mention auto-resizing somehow, but it seems like since the aspect ratio changes, scaling to the right size would leave the text looking "squashed".)
Finally is there some tutorial or explanation somewhere that explains clearly how the view controllers work? That also might help me answer my questions.
Docs on view controllers and learning related stuff
(1) Apple's UIViewController reference. Short and sweet (relatively).
(2) View Controller Programming Guide for iPhone OS. More wordy.
(3) Not view controller specific, but still: Cocoa Dev Central. Education with pretty pictures.
Nested View Controllers
The fact is that there are some key points that are a tad glossed over in the introductory docs. And I think a lot of the confusion arises from using the tab bar controller and navigation controller in particular.
For example:
You should not use view controllers to manage views that fill only a part of their window—that is, only part of the area defined by the application content rectangle. If you want to have an interface composed of several smaller views, embed them all in a single root view and manage that view with your view controller.
-UIViewController class reference
So, that certainly makes it sound like you should never nest view controllers, right? Well, from my experience, what they meant to say was something more like never nest view controllers, except maybe in a tab bar controller, or in a navigation controller, or in a navigation controller in a tab bar controller. But other than that, never nest view controllers.
View resizing
Another good question you raise: Is the coder responsible for sizing the view, or is that done by a view controller? And the usual answer is: yes, the coder is responsible for all layout and exact sizing of view elements -- except when that view is the first one added to a tab bar or navigation controller -- they tend to be somewhat aggressive about sizing your views for you. There are more details to know - things like autoresizing your view if the orientation changes - but this is a good rule of thumb to start with.
Views vs view controllers (and models)
Neither views nor view controllers are subclasses of each other. They're independent dudes. Generally, a view controller is more in charge, and tells the view what data to display, or where to position itself, etc. Views don't really tell controllers what do to, except perhaps to inform them of a user action, such as a UIButton calling a method in its controller when it gets pushed.
Here's a quick analogy to help understand the whole MVC model. Imagine you're building the UI for a car. You need to build a dashboard to display information to the driver - this is the view. You need sensors to know how fast it's going, how much gas you have, and what radio station is on - this data and direct data-handling stuff are like model objects. Finally, you need a system which knows when to turn on the low-on-gas light, or to turn off your turn signal when you turn the wheel far enough, and all the logic like that - this is the controller component.
Other stuff
A nib file is mostly a way to save view-related data that would make for ugly code. You can think of them logically as freeze-dried class instances, ready to use. For example, positioning a grid of 20 buttons that will be the UI for a calculator; a bunch of pixel coordinates makes for boring code, and is a lot easier to work with in interface builder. It can also accommodate view controllers because that code is also occasionally very boilerplate - such as when you need a standard, everyday tab bar controller.
About which view controllers control which views: Again, the tab bar and navigation controllers are kind of special cases, as they can act as containers for other view controllers. By default, you think of having just one view controller in charge of the full screen at a time, and in that case, there's no question that this one view controller is handling any delegated calls back from your view or other elements. If you do have some container view controllers, then it still makes sense for the most-specific view controller (the most nested one) to be doing all the dirty work, at least for the views which are not controlled by the container controllers (i.e. anything not the tab bar / navigation bar). This is because the container view controllers aren't usually considered as knowing about what they contain, and this agnosticism gives us better decoupled, and more maintainable code.
And, yes, in this context a view controller is always meant to be a subclass of UIViewController.
View controllers are simply that - objects that handle control of a view.
A XIB files doesn't "contain" a view controller. Instead it normally tells a XIB, what view controller it will be wired up to eventually - that's what the initWithNib call is doing, creating a view controller, getting the view out of the xib, and then attaching the view controller to where the XIB says it should connect to parts of the view.
There are nested view controllers technically when you use a navigation controller or tab bar, but your own view controller basically gets called as if it were the top level because those containers understand they will be holding other view controllers.
As for resizing - it's not a pixel resize, it's a container resize. The view controller resizes the master view it's hooked up to, then the auto-resizing behavior for any elements that view holds determines how they are resized - some things like lables might shift around, but by default do not shrink. If you click on the Ruler tab in IB you can see the current autoresize behavior for any object in a view - the center lines with arrows at both ends tell you if an object will allow resizing, and in which directions. The lines on the outside of the square tell you what side(s) the object will "stick" to, meaning the object will keep the same distance from those edges no matter how the container holding it resizes.
I'm not sure what the best book for IB is, but you probably cannot go wrong with a good fundamental Cocoa book which should explain autoresize behaviors.