Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In iOS, should every UIView have a UIViewController?

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?

like image 370
Evan Conrad Avatar asked Oct 18 '15 03:10

Evan Conrad


People also ask

What is the difference between UIView and UIViewController?

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.

What is UIViewController in iOS?

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.

What is UIViewController life cycle?

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.

What is the difference between viewDidLoad () and viewDidAppear ()?

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.


1 Answers

There are probably MVC gurus out there way wiser than me, but I'll give it a crack:

Option 1 - Failure

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.

Option 2 - Success

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.

Option 3 - Ehhh...

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.

To Summarize

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.

More reference:

Model-View-Controller - iOS Developer Library

Hope this helps!

like image 96
adamsuskin Avatar answered Nov 01 '22 12:11

adamsuskin