Many views have subviews that don't necessarily need to have their own controller associated with them. In Apple's own tutorial on creating custom views, they don't actually create a sub UIViewController for each subview.
However, often I run into situations where I'll have a view hierarchy where some subview of a subview has a button that sends a network request. In that case, I could do a target:
myView.addTarget(self, action: "networkRequest:", forControlEvents: UIControlEvents.TouchDown)
And then in the same myView class I could handle that network request, but that seems to break the MVC pattern. View's shouldn't do logic, they should just display stuff, correct?
Another option we could do is have each view have access to it's parent or grandparent controller that it needs for logic. In the case my target might look something like:
func networkRequest(view : MyView) {
self.controller.doNetworkRequest()
}
But that doesn't seem to be a correct solution either. Again, it seems like we're just breaking the MVC and weaseling out.
So instead, we're left with one of two options as far as I've seen:
First, we could add targets and all logic from the parent controller itself. But doing that gives us nasty chains like this:
self.grandParentView.parentView.childView.addTarget(self, action: "networkRequest:", forControlEvents: UIControlEvents.TouchDown)
That long list of accesses gives me the chills and just looks bad. But, it still seems to follow the MVC. Technically we're doing the logic in the controller, right?
But there might be another option. We could just give each view a controller and have each UIViewController have a sub-controller for each new subview.
But, some views are static. They don't really have any logic, so they don't necessarily need a controller. But, we essentially need one for each view if we're going follow this convention, otherwise we have inconsistencies where a controller has a grandchild controller but no child controller.
So we're left with creating a lot of empty caskets for our controllers. This builds up a lot of dead code that never gets used which can cause a bit of software rot.
So someone who's smarter and wiser than me, what's the correct solution here?
They are separate classes: UIView is a class that represents the screen of the device of everything that is visible to the viewer, while UIViewController is a class that controls an instance of UIView, and handles all of the logic and code behind that view.
The UIViewController class defines the shared behavior that's common to all view controllers. You rarely create instances of the UIViewController class directly. Instead, you subclass UIViewController and add the methods and properties needed to manage the view controller's view hierarchy.
The LifecycleThe view controller lifecycle can be divided into two big phases: the view loading and the view lifecycle. The view controller creates its view the first time the view is accessed, loading it with all the data it requires. This process is the view loading.
The difference between viewDidAppear and viewDidLoad is that viewDidAppear is called every time you land on the screen while viewDidLoad is only called once which is when the app loads.
There are probably MVC gurus out there way wiser than me, but I'll give it a crack:
If you are handling network requests in a UIView subclass, you are definitively breaking the MVC pattern. According to Apple's MVC reference:
A view object is an object in an application that users can see. A view object knows how to draw itself and can respond to user actions.
As it appears, a view is supposed to simply handle what users can see and interact with. Do not go this route.
Let's go back to Apple's MVC reference for view controllers:
A controller object acts as an intermediary between one or more of an application’s view objects and one or more of its model objects. Controller objects are thus a conduit through which view objects learn about changes in model objects and vice versa. Controller objects can also perform setup and coordinating tasks for an application and manage the life cycles of other objects.
Notice how the doc says "one or more," as in it is completely acceptable for a view controller to handle the logistics of multiple views. Personally, I'd say that if your view only has one button that needs a delegate for network requests, go ahead and set the parent view's view controller as the delegate.
You should let a view have its own view controller as soon as a view's data handling becomes "complex," which for conciseness I will define as "multiple actions that would cloud the apparent purpose of parent view's view controller."
That being said, it is possible to clearly mark in a view controller with #pragma mark
exactly why code is where it is, so use your judgement here.
Giving each view its own view controller is definitely viable, but do you really think it is necessary? Creating a whole new view controller every time you need to handle a single button tap certainly seems like overkill if the app is expansive.
Go with option #2 and use your best judgement. You can't get punished for breaking the MVC pattern. Worst comes to worst, you'll refactor your code into a new view controller if your view's logic becomes complex.
Model-View-Controller - iOS Developer Library
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With