Following the MVC design pattern for iOS apps using Storyboards in Xcode, I noticed that I can place IBOutlets for UILabels, UIImageViews, etc., into the ViewController or into the UIView itself.
Scenario 1:
Model Classes -> View Controllers (IBOutlets) -> UIViews in Storyboard Scene
the ViewController (VC) grabs the necessary data from the Model
IBOutlets in the VC are used to set the text and images that are in various UIViews in the Storyboard
Scenario 2:
Model Classes -> View Controllers -> UIViews in Storyboard (IBOutlets)
the VC grabs the data from the Model
the VC calls methods in each UIView subclass
those methods in each UIView subclass set the text and images in the associated UIView via the IBOutlets in that UIView
I found that Scenario 2 is more manageable when you have many UIViews and UILabels and UIImageViews in each view. The other approach can lead to a lot of IBOutlets in a single View Controller.
Which approach is best to follow when using Storyboards?
Your observation is correct, the second scenario leads to a more manageable design.
The difference between your two scenarios is primarily in their use of encapsulation: the first scenario encapsulates on the level of View+View Controller, letting the controller freely access things that should logically be part of the view alone, while the second scenario properly restricts access of IBOutlets to the view class, forcing the view controller to interact with them through the methods that you expose in your view.
As the consequence, the first scenario creates tight coupling between the view and its controller, while the second scenario significantly reduces this coupling.
Of course there is a tradeoff: you pay for reduced coupling with more code. Up to a certain point, it does not matter: when your views and their controllers are relatively small, it is easy to manage the combination of the view and its associated view controller as a monolithic object. The benefits of using the second scenario become more visible as the complexity of your views increases. This applies to all uses of encapsulation, not only to MVS in iOS scenario: the bigger your project - the more payoff you get from using proper encapsulation.
Related
When to use ContainerViewController? and does it have any advantages in memory management over normal views in iOS? In my application one of the screen is having two separate options which is responsible for different tasks. Should I use two ContainerView instead of two separate views. Which option will be more scalable?
Container views and parent/child view controllers don't have a meaningful impact on memory. You would need to have hundreds of view controllers in memory at once before different view structures would have a meaningful impact on your memory use.
Container views and parent/child view controllers are useful as a design pattern. It makes it straightforward to create discrete "tiles" of user interface where the views and the control logic that control them are one drop-in unit. Using parent/child view controllers is also the only way to make UITableViewControllers and UICollectionViewControllers useful, since those view controllers don't allow any other subviews in their view hierarchy.
From performance or memory management perspective it will always be equal or better to use UIView directly. From scalability it simply depends on what you are building.
A content view from storyboard is just a convenience. In general you can add any view controller as a child to another view controller by calling appropriate methods and adding the view as a subview. What you gain here is that your view controller will receive events that are specific for it while view itself will not.
In general view controller is just a wrapper around UIView. Application is designed so you need a root one but after that you might as well do everything with views alone.
Containers are used internally a lot. In reality view controllers may only present and dismiss. What you see as push, pop, set view controllers are all just using containers. Navigation controller consists of header and container view. Tab bar view controller has tab bar view and container view... Using containers you can easily create your own similar components.
When you use containers you will have a very clean code as you separate logic of each unit to its view controller. But at the same time your code may complicate because you now have trouble communicating between your view controllers. Imagine you have two parts of the screen where each represents a set of objects for a common model. Now it all goes well when there is no correlation between the two; but when first view controller changes an option which now needs to reflect in the second view controller you may need to report to delegate which is a parent view controller which will now report to the other child view controller. And even parent may have ugly code to access it's children. But on the other hand some MVVM procedure may handle this situation very nicely.
Anyway there are no apparent advantages or drawbacks. It depends on what architecture you will use and how you will use it. Both procedures are solvable and both can get ugly.
I have a UIScrollView, contains 3 pages.
The first two are UITableView, the third one is a UICollectionView
So in one View Controller I will have to write delegate methods for all of them.
I googled a bit and found a solution like this (not tested yet),
Place each page in a separate UIViewController, implement the
corresponding delegate methods, and use UIViewController.view
attribute to build the scroll view
The UIViewController.view approach seems wrong to me, is that the normal way to do it?
Why are you trying to handle all the delegate calls in one view controller, can't you create separate view controller for each of them? If you are not separating now then it will be tougher for you to manage code later.
Absolutely using controller composition is a standard and respected solution to the Massive View Controller problem. Examine for instance the expositions at the StackViewController project which cleverly uses that concept to create forms in a UIStackView:
Composition over inheritance is a fundamental principle of object-oriented programming.
This principle has always been used in iOS view hierarchies, where more complex views are composed out of simpler ones (e.g. how a UIButton contains a UILabel and a UIImageView that render its content). However, there was no "official" way to compose view controllers until the introduction of view controller containment in iOS 5. It was possible to mimic behaviour like this prior to iOS 5, but handling the propagation of events between parent and child view controllers and transitions between child view controllers was difficult to get right, which are all problems that the view controller containment API solves.
In the same way that you can create complex layouts by composing multiple UIStackView instances, you can use the view controller containment API to compose multiple instances of StackViewController to create a hierarchy of view controllers where each content view is backed by a corresponding view controller that cleanly separates the responsibilities, instead of handling all of that at the view level (an anti-pattern, as mentioned earlier).
Also review 8 Patterns to Help You Destroy Massive View Controller, particularly
Standard Composition
View controllers can be composed using the View Controller Containment APIs introduced in iOS 5. If your view controller is composed of several logical units that could each be their own view controller, consider using Composition to break them apart. A practical application of this litmus test is a screen with multiple table views or collection views.
Which is, in fact, the exact situation that you have to practically apply it to!
New to iOS, just wondering if someone could explain the point of the storyboard.
If i create a view controller and programmatically add to it, what do i need a storyboard for?
Is it only for custom views? custom tables? etc
Thanks.
Long story short, my understanding of storyboard purpose is as follows:
Less code -> less bugs
Visual representation of UI layout simplifies UI creation (views hierarchy, autolayout constraints)
Extremely simple way to set objects' properties (e.g. delegates, gesture recognizers) just by control-drag
From Apple's Document:
Storyboards
Storyboards are the recommended way to design your app’s user interface. Storyboards let you design your entire user interface in one place so that you can see all of your views and view controllers and understand how they work together. An important part of storyboards is the ability to define segues, which are transitions from one view controller to another. These transitions allow you to capture the flow of your user interface in addition to the content. You can define these transitions visually, in Xcode, or initiate them programmatically.
You can use a single storyboard file to store all of your app’s view
controllers and views, or you can use multiple view storyboards to
organize portions of your interface. At build time, Xcode takes the
contents of the storyboard file and divides it into discrete pieces
that can be loaded individually for better performance. Your app never
needs to manipulate these pieces directly. The UIKit framework
provides convenience classes for accessing the contents of a
storyboard from your code.
For more information about using storyboards to design your interface,
see Xcode Overview . For information about how to access storyboards
from your code, see the UIStoryboard Class Reference .
Background
I'm using interface builder to create the UI for an app I'm working on. The app has a single screen that displays a series of buttons. Clicking on a button displays an associated view which overlays the buttons. Clicking another button hides the previous overlay view and displays another one.
Too make managing the UI easier in IB I've decided to create multiple nib files for each sub view that is to appear when clicking the relevant button. I'm then loading the sub view's nib file in the view controller's viewDidLoad method using the UINib class.
The idea behind this was to avoid having multiple views stacked on top of each other in a single nib file as this would be hard to manipulate in IB. I could have created all the views in code but this would require a lot of tedious coding as the layouts of each sub view are quite complex (with multiple child views).
Example code loading a sub view from a nib file.
- (void)viewDidLoad
{
UINib *aSubViewNib = [UINib nibWithNibName:#"aSubView" bundle:nil];
NSArray *bundleObjects = [aSubViewNib instantiateWithOwner:self options:nil];
// get root view from bundle array
UIView *aSubView = [bundleObjects objectAtIndex:0];
[self.view addSubview:aSubView];
...
The code above is repeated for the other views.
To summarise I have a single screen iPhone app that has layered views that are shown/hidden by clicking buttons. This is achieved with a single view controller with an associated nib file and a series of additional nib files for the sub views which are loaded in the view controller's viewDidLoad method.
Questions!
Sorry for the long introduction but I wanted to be very clear what it is I am doing.
Is my approach bad or unusual?
Are there any potential issues to doing it this way?
What have other people done when they need a dynamic interface and
still want to keep everything in Interface Builder?
Notes
Before anyone asks why don't I just display the sub views on a new screen and use the navigation bar, let me say that I have very good reasons and I do understand iOS UI guidelines. The above use case is not exactly my use case but it's one that clearly describes the problem without getting bogged down in my development app.
Also I know I could have written all the sub views as code but each sub view has a complex layout of child views and it would be a lot of code and messing around to try and get them looking right.
Thanks in advance.
There isn't necessarily a 1-to-1 relationship between view controllers and views. Most views contain many subviews, which are views themselves, so this literally doesn't make sense.
However, depending on the complexity of the views (including their content), you may want separate view controllers... or not.
For example, if you have two sbuviews that are each tableViews, you may want to have one view controller for each tableView. This is because each tableView is looking at the same delegate methods, and if they are in the same viewController, then the delegate methods have to differentiate between the tableViews. The delegate methods have signatures that allow this, but, in my experience, it can really make for a messy code design that is hard to follow and hard to manage.
On the other hand, you may have two tables that are managed by the same viewController, where one table is filled with meaningful data and the other is simply a place holder (as when the data source is empty). One might be visible while the other is not. Why make you life complicated by creating two view controllers when both are driven by the same data source (the model)?
In my mind, it comes down to how difficult it is to follow and manage the code. If the complexity of using a single view controller becomes burdensome, consider using more view controllers.
UPDATE
By the way, I have an example that I am currently working with that may illustrate a similar situation. In the InAppSettingsKit, that a lot of developers use, there are several xib files for pieces of the main view. You can look at the structure here on github. There is one main view controllers and several xib files. (There is also what I would call a "helper" view controller and an email composer view controller.) In this example, the xib files may be used multiple times to specify the layout of table view cells. There is no view controller for each xib file, though. (The documentation for InAppSettingsKit is sparse, so these things may not be obvious just by taking a quick look at it.)
Every View should have a corresponding UIViewController. Using one ViewController to "Control" more than one view breaks the MVC paradigm. "Controlling" multiple "views" from one controller will make it much harder to change one thing without breaking something else. The choices you make on how to present the content to the end user will be different for every individual. So if you say a NavigationController won't work in your case, maybe a Modal view is the answer or, you might just instantiate your custom UIViewControllers and add them to your view ([addSubview:]), if thats the road you want, but like I said, it would be beneficial for you to make a "controller" for each view object along with the corresponding xib. If you need information sent back, use a delegate or use Notifications to send the message back to the parent view. I learned the hard way that not following MVC paradigm, will make you life miserable. Try and keep your code as decoupled as possible. And read up on the MVC design pattern, you won't regret it.
actually its possible to do this.
Open your .xib file,select File’s Owner(in placeholder) -> "identity inspector" (utilities) -> change class name to your controller classname -> press control and drag file's owner placeholder to View object, select "view" in dialog.
Now you can customize your view.
p.s. you can use the same outlets as first xib, you need only to drag them to the new xib(+control sure).
here is an explained tutorial:
http://irawd.wordpress.com/2013/09/05/how-to-link-a-xib-file-to-a-class-and-use-2-xib-files-for-iphone4-and-iphone5/
I would like to develop an application for iPad, using a layout like that shown in this link:
https://skitch.com/sparkoletto/g13ck/ipad-views-layout
As you can see in the image on one page I would like to insert a UITableView (B), two UIScrollView (one vertical (D) and one horizontal (A)) and a simple UIView (C).
What is the best way to develop such interfaces?
It 'best to use a single ViewController that manages all the views that I need, or create a ViewController for each view, and then combine them all together in another UIViewController?
Thanks
I disagree with #TomSwift. When these things get complicated, it's very helpful to break them out into their own view controllers. You'll create a view controller of the correct type and then [self.view addSubview:vc.view] at some point.
The problem with making one complicated view controller is that it becomes delegate and datasource for too many things that are internal details of individual subviews. Your delegate methods now need to check which tableview is talking to them, for instance.
Splitting them up also makes it much easier to manage rotation, particularly if you want a different set of views displayed in each orientation. This is good for memory management as well, since the VCs can automatically unload the views you aren't using anymore.
Breaking things up too small is of course also a problem. There is a cost to having separate view controllers, especially if they interact with each other. Having a good feel for when is the right time is the mark of an experienced developer. But for the view you showed, I would almost certainly break it up. Your situation looks very much like UISplitViewController.
Likely a single view controller, IMO, unless you plan to reuse some of these panes in other places. In which case you could implement a "container view controller" with a single view to handle the layout of the child view controllers.
Typically view controllers manage "full screen" (or nearly full screen) views. The exceptions are fairly rare - UISplitViewController is one.