Need advices on iOS MVC - ios

Based on Apple's document:
The View is never communicating directly with Model. Instead it's through the Controller.But I have a case which need to customise my UITableViewCell or UICollectionViewCell.
The customised view is very complicated. If I put all the logic in my view controller. It will become very difficult. Instead if I put the logic thus the model in my view. Then the code will be cleaner. But it disobeys the Apple's MVC principle. My question is how you'll handle this scenario? Is there any elegant way to handle this? Thanks.

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.

How to handle huge view controllers so code is not dirty?

I'm having a problem with the app I am developing right now : one of my UIViewControllers is huge ( around 3000 lines ).
For now, I created extensions of this view controller to handle delegate methods in order to "split" this controller. For instance, I have my main view controller called XYZMainViewController and as this controller is the delegate of a UITextField, I created an extension XYZMainViewControllerTextFieldDelegateExtension.swift in which I manage UITextFieldDelegate methods.
It's still pretty dirty to do that this way. I'm wondering what would be a good practice to handle huge controllers like this one.
did you consider to design your app using MVVM (model view view model) the idea of MVVM is to avoid huge controllers. There are a lot of user guides out there which explain how to use MVVM in your IOS app. I was facing the same situation half a year ago and then i adopt MVVM in my app and i am very happy with it since my controllers are not huge, i can reuse code easily in my app and also it's much more easy to create unit tests.
Please follow this guide which explain what is MVVM and how to use
ithttps://www.raywenderlich.com/74106/mvvm-tutorial-with-reactivecocoa-part-1
https://www.raywenderlich.com/74131/mvvm-tutorial-with-reactivecocoa-part-2
3000 lines is hmmmm hugeeeeee.
You have performed huge numbers of tasks in your controller. Controllers are supposed to control views.In my opinion(the way i create my iOS app structure) controller is suppose to perform view control,passing data from models to view(more specifically from classes which manipulates data).
"Separate of concerns" is important here. Don't implement your business logic inside controllers. There should be a separate module which do all of your business logic. How to manipulate models and complete a functionality. Then this class is used by controller to perform view updates.
No matter what type os view you have designed ,its controller can't be of 3000 lines. Delegation is not a problem. Controller is a good place to do delegation. Inside those delegate methods ,to perform some business is not the work of controller. There are some design patterns for IOS apps like MVC, MVVM.
But still you have to use "these design patterns efficiently. move the common functionality in one place etc. Implementation of business logic. Manipulation of models. Communication with DataBase.
Thanks.

Will handling UIButton touch event inside a UITableViewCell subclass violate MVC?

There is a UITableViewCell subclass with a UIButton inside. A web call should be made when the button is pressed.
The question is whether I should set the action in the controller, or can the action be set within the UITableViewCell subclass? Will the second option violate MVC pattern?
The second option will certainly violate MVC pattern. ViewController works like a glue between your models, views and contains all the business logic.
ViewController should receive action then make your api call and put formatted data to your views.
Usually in my project I always try to move networking code into separated set of classes which can handle fetching data from API, transforming from JSON/XML to model objects and formatting them (string date object to NSDate object etc.). Then I can call simple looking method in my ViewController and populate views/tableview cells.
On the other hand,
If you have some time you can look at MVVM which is getting more popular.
There are some links (start with sprynthesis which is AWESOME):
www.sprynthesis.com
objc.io
cocoasamurai
raywenderlich
And some sample apps:
C-41
vinylogue
GroceryList
That helped me to understand MVC more deeply thanks to comparision to MVVM.
Don't be scared with usage of ReactiveCocoa, you can always adopt MVVM without it but it's worth to look at. (It has really steep learning curve and I still feel like an idiot)
Also there is a great article about design patterns with iOS implementation:
raywenderlich design patterns
Well you can delegate the action to the controller from the subclass, that way it'll be handled in the controller, clear, and doesn't violate MVC.
I don't recommend to set the action within the UITableViewCell. What would you do if you need to wait for the answer and the cell needs to be recycle? I will set the action in the controller. This controller should call another class in charge of performing the web call.

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.

What is the appropriate design pattern for the following situation?

As an exercise I am working on a simple drawing app for the iPad.
I am using UISplitView, with the drawing view as the detail view. In the master view controller I present (in a table view) a list of the shapes drawn so far.
The user can edit or delete any shape from the master view controller, and also select and edit a shape by touching it in the detail view controller.
To notify each of the view controllers of the changes made by the other, I thought of using delegates, but I am not sure if this is the right pattern to use.
First, as I understand it, delegates are supposed to be used when a certain object encounters an event which they don't know how to handle. in that case they pass all the information to the delegate and let it handle the event. This is not the case here since both view controllers need to do something with the information. Using delegates here can cause code repetition.
Another reason I am thinking not to use delegates is that in the future I might want other view controllers to get the information of changes in the drawing. I can use multiple delegates (is it good practice in general?) but I'm not sure this is a good solution either.
Are there other solutions I should consider?
On the contrary, I think delegates might be the right pattern to use here - you don't necessarily delegate only when you can't handle an event (though that might be one situation where you would delegate).
Instead, consider delegates a way of getting information to or from another object, when you simply don't know what that object might be. For example, Apple uses the delegate pattern when working with UITableViews; in that delegate protocol, the table view knows perfectly well what to do in each situation, but still notifies your code when certain actions are about to happen. I think that's an excellent parallel for your situation. (Note that a parallel to your question's assumptions also exists, in the UITableView "data source," where the table view does require some bits of information.)
Another technology you could consider using, if you're really dead-set against delegates, would be to use notifications. You can have each controller subscribe to particular notifications, then have your shape (or detail view controller) post instances of NSNotification when observable changes happen. That way, you still get to handle events happening in a different controller, but without needing to maintain a delegate list.
As for code duplication, just consider refactoring as you start encountering situations where you would duplicate; maybe you should design a single delegate or notification subscriber object for the common code, then only do class-specific things in each of the other controllers?

Resources