I was left with continuing the code of a senior developer, where I came across a coding pattern that was not only bizarre, but got me curious about a lot of things. The pattern, however, that I spoke about had something like this:
There is a UIViewController the view of which has an instance of extended UIView attached to it as a subview.
This custom UIView class has a reference of the above-stated UIViewController.
There are a series of methods defined within the UIViewController that are responsible for handling events at the UIView.
Since this UIViewController exists as a reference, our custom view calls those event-handling methods through this reference!
In such a system of code, what are the memory implications? How is this any different from the delegate pattern? Under what circumstances using this sort of coding okay?
While this pattern is a little curious, I would hesitate to condemn this without more information about what this child view is doing and what it needs to inform the view controller about. There is, admittedly, a faint code smell here, and if I were to hazard a guess, I'd bet that this view is likely doing stuff that one would now generally put in a view controller.
Often, when adding a subview that has any significant complexity (or is likely to be reused in different views), one would consider an iOS 5 feature, "view controller containment" (see the Creating Custom Container View Controllers section of the View Controller Programming Guide or WWDC 2011 video Implementing UIViewController Containment).
If using storyboards, you can achieve much of this using the special "Container View" control introduced with iOS 6, found in Interface Builder's "Object Library" (in the bottom of the right panel in the standard Xcode layout). If doing this programmatically, just make sure to call the appropriate methods listed in the "Managing Child View Controllers in a Custom Container" section of the UIViewController Class Reference.
When using view controller containment, you have a parent view controller (the main view controller) and the child view controller (the view controller that is managing the subview). And in this scenario, it's very common to design a custom protocol by which a child view controller notifies its parent view controller of particular events. But rather than adding your own custom delegate property, you can use the built-in parentViewController property which is automatically populated when you adopt the above "view controller containment" pattern.
Having said all of this, I might let practical concerns drive whether the existing code base needs to be refactored or not. Perhaps the code predates iOS 5, but is a solid implementation of what we might have done back in the day. Bottom line, if it works, is otherwise well written, and has the delineation of responsibilities clearly defined, you might decide to just leave well enough alone. And if it's a little ambiguous (as the absence of a discussion of a protocol might suggest), perhaps just start by introducing a formal protocol between the child view and the view controller to make the interface explicit. Whether a more radical refactoring of the code (to use something like view controller containment) is called for is hard for us to advise on the basis of the limited information provided thus far.
Related
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!
Reading several tutorials and books on iOS development I often encounter terms : UIViewController life cycle and UIView life cycle. I'm interested: is there an actual difference between these two terms?
Looking Apple docs I found that methods such as viewDidAppear or loadView is a part of view controller's life cycle, but I think it is more correct to refer them as view life cycle and methods such as initWithNibName or dealloc as controller's life cycle. Or there is no such a separation and when someone speaks about view life cycle he actually means UIViewController life cycle?
Both are different concepts, therefore have different life cycles.
UIViewController
A ViewController is the Controller in a MVC architecture. Therefore, it is responsible to coordinate the info between the model (your data) and your views. UIViewControllers coordinate the UIViews and are part of navigation between screens (pushViewController, presentViewController). Therefore it needs to know when it will appear in the screen.
A UIViewController has a very specific life Cycle and it has methods that can be extended that are part of that life cycle. Examples of those methods are:
viewDidLoad, viewWillAppear, viewDidAppear, viewWillDisappear, viewDidDisappear
View
A View, on the other hand, shouldn't be worried when it has to appear on screen. Therefore, it has a complete different life cycle:
awakeFromNib, willMoveToSuperView, didMoveToSuperView
This methods usually are called in the sequence of the UIViewController's life cycle. Therefore, normally, the UIView responds to changes and people don't consider they have a Life cycle on their own.
The ViewController's life cycle only makes sense when a class extends UIViewController while a UIView's Life cycle only makes sense when extends UIView.
Most of the times, when people talk about Life cycle they will talk about the UIViewController life cycle, since the View usually responds to changes. Two examples of those changes are: the view changed its size, changes its parent.
All your confusion will go away once you fully realise the difference between the two classes and ingrain it into your mind (by practice)
UIViewController - a class that has no UI in itself (not completely true though...see root view), its purpose is to control views and do some related stuff..It is like a policeman or traffic controller policing others. (views).
Most of the time you create your own subclass of UIViewController and that class tends to be quite heavy on functionality like
handling logical rules when to show what view
connecting to model layer (data and facts about the problem your app is solving)
interacting with other controllers,
UIView - a class that represents a rectangle area that can be heavily visually modified, but the most important fact is, it is visible on the screen, and can have subviews, which are also UIViews. Views are organised into view hierarchies.
Most of the time you customize your view so that it is
visually pleasing
handles it's subviews via autolayout
represents the particular type of visual information you need often subclassed to a more specific view class like labels, texts, buttons, etc.
One bit that confuses newcomers is that every view controller has one root view, a property which holds a UIView instance. Often you can get lost as to whether this root view is discussed, or the view controller is discussed. In causal discussion between developers, the two words are sometimes used interchangeably.
Both controllers & views have the lifecycle but you must not confuse the two.
ViewController lifecycle is what happens to the controller itself, like it awakes from nib file, or receives a low memory warning, but mostly about how its root view comes to life, how it appears disappears and dies..
View Lifecycle is about how the view lays out its subviews, and how it renders its content.
I like visual analogies..
Simply imagine a policeman with a lot of colorful paper rectangles. The policeman is the controller, and he says what (views) is shown and when on the screen.
The controller and the View are abstractions that are part of (Model View Controller) MVC architectural pattern. I recommend you study that immediately, so that the problem with lifecycle confusion is further cleared in your mind.
Adding to these answers and focusing a bit more on your exact questions:
I'm interested: is there an actual difference between these two
terms?
Yes, there is a different between both, but in a context where you are dealing with a UIViewController's root UIView, they are in a way related.
Looking Apple docs I found that methods such as viewDidAppear or loadView is a part of view controller's life cycle, but I think it is more correct to refer them as view life cycle and methods such as initWithNibName or dealloc as controller's life cycle.
And this is why they are related:
viewWillAppear
viewDidAppear
viewWillDisappear
viewDidDisappear:
They are all under Responding to View Events in the documentation. So these are callbacks from the UIView to the UIViewController telling it about its state. And although:
loadView
viewDidLoad
Are not under the same section (in the documentation), it's the UIView requesting/telling the UIViewController about its current state. And you have other examples of these interactions, for example:
viewWillLayoutSubviews
viewDidLayoutSubviews
In a way (and in your question's context) the general answer is: yes, those are two different lifecycles with different particularities, but they are related in a way. An example where they are not directly related would be the UIViewController's didReceiveMemoryWarning. (I say directly, because indirectly, it might be the UIViewController's root UIView the culprit).
Most of the lifecycle is handled automatically by the
system and no need for calling some methods like parent and child view
controllers relationship
Here are the mentioned lifecycle methods for UIView:
didAddSubview(_:)
willRemoveSubview(_:)
willMove(toSuperView:)
didMoveToSuperview
willMove(toWindow:)
didMoveToWindow
I am trying to utilize transitionFromView:toView:duration:options:completion: but in uiview class reference this point is confusing me. What it means?
This method modifies the views in their view hierarchy only. It does
not modify your application’s view controllers in any way. For
example, if you use this method to change the root view displayed by a
view controller, it is your responsibility to update the view
controller appropriately to handle the change.
Please view the sample project https://anonfiles.com/file/521cbb41b086eae987fe27eb98278aba
In this project I just called transitionFromView:toView:duration:options:completion: and everything is working fine and did nothing what is mentioned in the above point.
You are more likely asking for an explanation of Apple's documentation than a specific question, if I understand your posting correctly.
Nevertheless I'll give you this explanation and I hope, it will help you:
You write:
Everything is working fine..
and that is, because you a doing well here!
According to the MVC design pattern (Model-View-Controller), you are using the classes UIViewController (the "C") and UIView (the "V") in your code.
A view contains the visual representation of objects (like labels, buttons, subviews, ...) without an logic for their behavior.
A viewcontroller provides the logic, e. g. IBAction methods and any other methods that you may implement.
Each UIViewController has its own "view" property containing the view, whose behavior the controller does manage. This view normally contains additional views, e. g. labels, images and buttons. They are subviews and are stored in the view's "subviews" array property. Btw, each view has such a subviews property - that is, how we can implement complex view hierarchies.
In your situation (multiple subviews that are managed by one common viewcontroller), the method
transitionFromView:toView:duration:options:completion:
hides "fromView" and unhides "toView" with the support of animations. It is a transition between to views. The paragraph from the documentation shall prepare you as a developer, that this method only manages the change of the visual representation and does not provide additional "services" for your view controller for the further management for the participating views.
That means, that you have to manage e. g. the state of the views (which view actually provides interaction for the user) by your own code. It seems to me, that you have managed this well!
In a wider scope, iOS supports UIViewController container as well - they can contain child view controllers (which again contain their view with its subviews). In such an architecture, there is another transition method from the SDK,
transitionFromViewController:toViewController:duration:options:animations:completion:
which allows you to implement transitions not between two views, but between two view controllers.
I hope this is not too much text and helps to make things clearer for you.
I'm writing an app that has two sections like this:
The idea is that on the top half I'm creating a request, and on the bottom I'm displaying the results. As my UIViewController subclass grows and grows I thought it might be a good idea to split that into two UIViewControllers. (So what I'm trying to do is something like a UISplitViewController).
Although I know it's possible programmatically I'd like to put both UIViewControllers in the screen from the Interface Builder so I can manage autolayouts and design there. Dragging and dropping doesn't work there.
Is that possible? And more important - is that a good design or should I stick to the rule "One view controller for one screen"?
You can use a custom container view controller to achieve what you want. See:
WWDC 2011 #102 on UIViewController Containment (Apple developer ID required)
the containment section of the View Controller Programming Guide
the containment section of the UIViewController Reference document
In short, since iOS 5, you no longer have to have a single view controller. Just make sure you call the necessary containment related calls. And iOS 6 makes it easier to design the storyboards for custom containers with the "container view" object.
Apple have stated (WWDC 2012, Evolution of View Controllers, I think) that the "screenful" is no longer appropriate. A view controller should manage a self-contained chunk of functionality.
As of iOS5 you can compose an interface of multiple view controllers using view controller containment (addChildViewController: and so forth). As of iOS6 you can do this in interface builder using containers and containment segues.
You will of course need a view controller to hold your two child view controllers - this will hold a screenful of content, and will usually perform any coordination between the two children.
The name "View Controller" in iOS programming is a bit confusing as it includes both words "View" and "Controller" in the MVC model. Is "View Controller" actually just another name for Controller (as the view is actually mostly done by the Interface Builder). Why is it called a "View Controller"? Is it because this controller does all the view properties updating and event handling as well?
Yes, a UIViewController lives inside the "Controller" layer of MVC. But it is a special controller that controls and updates a view. View controllers can also handle events because they derive from UIResponder.
You can also create general controllers by subclassing NSObject. For example an accounts controller that manages accounts etc. You actually find other controller classes in the iOS SDK, e.g. UIDocumentInteractionController.
From the iOS View Controller Programming Guide:
For iOS applications, view controllers provide a vital link between an
application’s data and its visual appearance. Understanding when and
how to use view controllers is crucial to the design of iOS
applications. View controllers are traditional controller objects in
the Model-View-Controller design paradigm but they also do much more.
In iOS applications, view controllers provide much of the logic needed
to manage basic application behaviors. For example, view controllers
manage the presentation and removal of content from the screen and
they manage the reorientation of views in response to device
orientation changes.
"Controller" follows the thing being controller. If I were writing a controller for a chair I would call it a ChairController. Since a UIView is being controlled, it makes sense to call it a UIViewController right? The view itself is only responsible for display, but the logic of what to display is up to its controller.
From Apple docs - http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html
The UIViewController class provides the fundamental view-management model for all iOS apps.
Basically it is the container for your views and handles more logic than just the visual display that your view does.
Where necessary, a view controller:
resizes and lays out its views
adjusts the contents of the views
acts on behalf of the views when the user interacts with them
You should see a "View Controller" as a "Class that controles the view".
This is a classic Model View Controller pattern (MVC).
A UIViewController has a view of type UIView and you update this UIView depending on your business objects (Model) for each particular controller.
Also, events that occur on your UIView, are sent back to your UIViewController for handling them properly.