Storyboard design pattern (to share or not to share) - ios

This is probably largely preferential but I'd like to know if there are any reasons to decide one way or another on this.
When designing with storyboards you invariably end up with a number of view controllers. I'm looking at the overhead of a strict MVC approach where each controller is implemented in its own UIViewController subclass with corresponding UIView subclass (and even view model class for MVVM), and that seems to get out of hand quickly – it takes no time to add dozens of files to the project (many with little function). An alternative approach would be to link all the views to a common controller representative of all of the storyboard functionality.
My inclination is that if you don't have substantial controller code for any individual view controller, then the combination of all of them into one shouldn't be of harm to the readability of the code (and may enhance it over adding a large number of source files). On the other hand, if you have significant functionality to implement for any particular view controller, then it should be encapsulated within it's own controller.
In most situations I'd build all controllers to be as reusable as possible (encapsulated in their own custom UIViewController subclasses). Storyboards put this in an interesting light though since they seem to be geared towards sequences of views that typically have few entry points.

Your thinking is correct
If you don't have much functionality in each VC (ViewController) them combine all your code into one VC. The only drawback to this approach is that you won't be able to implement view specific code and every view where you will use this common VC will execute the same code whether its needed there or not. e.g. code in viewWillAppear etc.
Similarly if you have a lot of functionality for a particular view then its better to put it under its own VC
This is just a suggestion, if you need to use some common code logic between multiple VCs then instead of doing copy and paste in each VC of the same code, make it into a method of type Category and then call it where ever its needed. So change the code only at 1 place.
More VCs doesn't necessarily mean bad design. In my opinion its easier to maintain that way. My two cents. :-)

Each scene in your storyboard should have its own UIViewController subclass. Even doing it like this it's way too easy to get huge unmaintainable view controllers (MVC = Massive View Controller). Putting all the code for multiple scenes in the same view controller would create even bigger ones and also violate the Single Responsibility Principle. Each class should do only a single thing.
That also means you shouldn't duplicate the common functionality into all your UIViewController subclasses. Then they again would do multiple things - the common stuff and their actual purpose. Instead you can put your common code in other controller objects (which are not descendants of UIViewController) and use them in your view controllers.
Depending on the usecase a common base class would work as well, but it's always preferable to use composition instead of inheritance.
Another nice thing about other controller objects is that you also can add them directly in Interface Builder and connect actions and outlets to them. Your main view controller class often doesn't even have to know they exist.

Related

When following MVC design pattern what code should be in the UIViewController class file? - Swift4

I'm trying to understand how to properly implement MVC in swift. Heres my scenario:
I have a signup page with 9 UITextFields, and they're all being made programmatically, and therefore being anchored to the view programmatically. As you can imagine this would be a lot of repetitive code to have in the SignupViewController class file.
Is the convention when following MVC to keep the setup of these text fields in the SignupViewController file, or are you supposed to have a separate file such as SignupView that contains all the text field setup code?
Even though UIViewController has the word "controller" in it, I believe the majority of iOS devs these days assign the UIViewController to the "View" side of MVC. The UIViewController is chiefly specific to a particular view only, plus may manage its subviews as well (until this gets too messy and a container view is added to allow for a nested UIViewController).
In MVC on iOS, the view controller can easily become polluted with business logic, model management, etc... which is why many people jokingly refer to "MVC" in iOS as "Massive View Controller". To combat this, consider using an MVVM architecture instead, which not only keeps the VCs small, but also moves the business logic out to a separate "sidecar" coupled to that ViewController, called a ViewModel. This allows the business logic to be unit tested without any UI involved, making testing much more reliable and easier to read and maintain. With that said, the creation of these 9 controls would still belong in the ViewController.
As for programmatically adding UITextFields to your view vs viewController, if this is to be done just for this single scene, then I'd stick it into the viewController. If you expect to want to reuse the set of them in other scenes, then making a custom view or control containing them would be better, like is typically done for custom cells of a table.
Finally, consider simply using a Nib or Storyboard to layout your scene. Apple has provided so much power to layout and maintain scenes via nibs and storyboards that you're really missing out to go the programmatic route. I find it very rare that I side with programmatic approach. The auto-layout warnings in InterfaceBuilder alone are worth gold to me, and as Apple continues to raise the bar and change layout rules, I can't imagine trying to keep up programmatically when I can't afford to test every device and iOS version combination. And yes, it's possible to do MVVM with dependency injection and storyboards. I do it daily.
Answer to your question is that it has nothing to do with MVC .
AS iOS/Mac developers, we use Interface builder and auto_layout to achieve most UI #IBOUtlet/ #IBAction. This is the V side of MVC.
Typically, If you have data, database, json or whatever formats, you need to model them and handle logics. That'M of MVC.
The C(Controller) side of MVC is a kind of glue between M and V. In most cases of mobile , you can think Controllers are all C you need.
So controller class is the only portion you need to put code to simplify everything.
In your case, 9 UITextfields should be ideally put into V side job. Please don't write code for them unless there is no better way to do.
I don't agree with above statement about using Interface Builder... I prefer to write most of my views in code and also set the anchors that way as well.
to minimize the file you can create an extension of the ViewController in a separate file to contain all of this code.
so for SignupViewController you would create a new file called SignupViewController+SetupUI.swift.
import UIKit
extension SignupViewController {
// add your setup methods here
// as just an FYI you can call the methods you create from your
// SignupViewController file just like you would any other method.
}
you can read more about extensions here.
After reading about good practices to write maintainable and readable code you should do the whole design in interface builder. If you get good understanding of constraints you don't need to write any code to setup design in your view controller. The ViewController.swift file should not be used to fetch-handle data or to setup the UI. It should just be responsible to display and update values which are fetched and get handled in a separate ViewControllerDatasource.swift file. So to sum up, view controller does not have any logic implemented it just handles the show data and the design updates(not setup). I hope i helped you with your question.

iOS controllers for custom views

I'm all for trying to create lightweight view controllers (testability, separation of concern, etc. etc.), however, I've been unable to find a reasonable solution or pattern when it comes to certain cases.
A very common case (with plenty of examples out there) is separating the view controller from a tableview's delegate & datasource; I get this, it makes complete sense. But what about cases where a view controller may contain multiple custom views of varying complexity? What should be responsible for controlling each of those views? Surely not just the parent view controller.
I tend to think of a 'UIViewController' as more of a screen controller that is heavily coupled with the UI framework and its events; it does not have a single responsibility of controlling one particular view. To further illustrate my point, imagine a tableview with a couple of different prototype cells - some of which are fairly complicated and may require network access for instance - how should this be managed? Surely no single view controller, datasource or delegate should act as the "controller" for all of these cells? And a lot of that logic/responsibility does not belong in the cell views themselves, so it needs to be delegated somewhere.
One option I've thought of is to just create controller objects (subclasses of NSObject) that act as "view controllers" for the custom views I create, such as a controller object for a complex tableview cell - its single responsibility is to manage that one particular view. The tableview cell then delegates to the controller object, which then (if needed) delegates back to the parent UIViewController. Whilst this will work and helps to separate concerns, it starts to feel a bit awkward with all the layers of delegation going on.
Does anybody have any good suggestions on handling these scenarios or know of good code examples out there that demonstrates this?
Thanks!

How can I clone a UITableView from one controller to another so it stays in synch?

I found this in SO; it doesn't exactly answer my question, which is: is there a way to clone a UITableView from one controller to another while using Storyboards and maintain synchronization?
You can clone them in the sense that their initial property values remain the same, like position, layout etc. For this, just copy the UITableView from storyboard, go to destination view controller and paste it there.
If you share same UITableView object between two view controllers, it is still possible, but you must estimate how much work you would have to do yourself. When a view controller solely handles a table view, much of the work is done under the hood and table is handed over to you. In case of your UITableView shared between two view controllers, you would have to play with it quite carefully. You need to take care of entire life cycle of the view - see the usual methods like viewDidLoad, viewDidAppear and so on. How would you take care of them when your view exists in two scenes? Maybe you would be inventing a unique design pattern - if at all you find the most optimistic and programmatically correct way to accomplish it.
With storyboards, you cannot achieve cloning up to the level wherein data changes will reflect seamlessly between the two. Storyboard is, as the name suggest, just a board, where you can draw things to know how would they look initially, before your code takes over.
In order to achieve what you want, you have to create a shared model that updates two table views through proper delegate methods. Most likely such a model (NSArray, or any such collections as per your requirement) can reside inside a shared class (app delegate isn't a wrong choice), from where both your view controllers can refer to it. That is neat practice, it not only is right from programming perspective but also extensible and helpful to anyone who deals with the code any time.
For details about how to update UI from your model, there is nothing better than starting from scratch, going through the books I mean.
I am not aware of such possibilities.
I would pass the tableview source object amongst different controllers and let the view controller handle their own table view.
I think the best approach would be to use a framework such as the freely available Sensible TableView, then use the same model for both table views. This should be really straight forward.

iOS - dealing with large and growing UIViewController classes

I have a UIViewController that over time has had a lot of delegate events added to it which has made the controller class quite large. The UIViewController class contains quite a few view-management methods that are called from the event-delegate methods to manage the UIView that the controller is managing.
I am now adding further UIActionSheet delegate events to the class. My controller class is getting large and I'm thinking that I should break out the UIActionSheet delegate events and place them in a separate delegate class. This separate delegate class will then have to call back into the view controller class to get the view controller to adjust the view accordingly, using the view-management methods within the view controller. (The view controller accesses a separate model object that the view is representing).
I can see pros and cons to adopting this break-out approach. It feels wrong to be adding more and more delegate events to the controller, but creating separate classes for different categories of events that then need to call back into the controller also seems to introduce an unnecessary layer of complexity and obfuscation. The large controller class is 'simple and straightforward' but feels wrong, whilst using numerous different delegate classes will be somewhat more complex and involved but will result in smaller classes.
Can anyone provide some words of wisdom on this topic, and perhaps point me towards some iOS-specific reading on the matter?
Many thanks.
My approach to this matter is:
Make it work
Make it cleaver
Back to 1.
(Or 1 and 2 both in same turn if you are experienced in a field)
So if code works app looks good but you find that ups some class has 100 methods in it so try different design patters (if you haven`t already) and use those cleaver ideas to make code separation into different classes, delegates, encapsulate them if necessary et.
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaDesignPatterns/CocoaDesignPatterns.html
Just in case link to Cocoa Design pattern suggestions and i am from time to time looking into Pro objective c design patterns for ios. Might be not the best book out there but it is based on "Gang of four" design patterns book in ios context.
Hope this helps at least somehow,
Cheers
In the end I created quite a few additional classes for dealing with specific UIActionSheet instances. I created a base class and then subclassed this for each UIActionSheet requirement within the main controller.
The end result looks tidy, and doesn't add too much complexity.

What is the best practice to control multiple views?

I have this view in the storyboard:
as you can see there are some fixed controls, and others that change according to the type of screen.
What do you think is better?
1- Same view controller for multiple screens. (more code to control views)
2- Add all controls in the same screen, then hiding and showing them by code? (messy code)
3- View controller for each screen. (replicated code)
Don't use the word "window", which can lead to different interpretations of what you are trying to say. Use the word "screen", or "section of the screen". In this case, I would use a container of UIViewControllers. To communicate between then, use KVO or NSNotificationCenter (most probably the second one). Also make sure to not have the data source directly on the UIViewController (like an array or a dictionary). Keep the Data Source somewhere else, where all the UIViewControllers (or any class) can easily access. You could go with a Singleton.
Putting the Data Source away, and not directly on the UIViewController, gives you more flexibility over your code. If you ever need to use a new UIViewController, nothing is changed, he can still request resources from the same point. So keep that in mind.
Edit 1
The data source also is inside the view controller, there is no
interaction between screens, it's the same screen but some controls
changes according to the type of it, what do you think I have to do
now?
The problem with this kind of approach is that if you need, for some reason to add a new UIViewController, that also use the same data source, what do you do now? I always try to decouple as much as possible the UIViewController from the Data Source. Otherwise you might have problems in the future, if the application changes (client's needs change). Again, moving the Data Source to a proper class, and use a Singleton to access it.
UIViewController <=> Singleton <=> Data Source
So now you suggest to make multiple view controllers with multiple screens?
I suggest a UIViewController to act as a container for the others UIViewControllers. For me it makes more sense to compose the Screen as I go, than doing everything in one place.
I'd definitly go with no 3. This approach is most flexible! And it is clean => good to maintain

Resources