KVO and MVC Question - objective-c

Simple question here... Is it alright in terms of MVC design to observe a value in the model from a view (using Key-Value observing), and update the view's current location on the screen based on when the model's variable changes?
Is it okay to observe from the view object and have that object move itself when the Location variable inside of the model object changes?
Or is this against MVC because the view and the model are communicating in a sense?

You should tie it through a C, controller, item. Even if it means you're pulling in the state data from the model, and then having the controller set the view or the view read that data from the Controller.
The view and model should always be separated by a controller. That's MVC according to Apple. The reason is that even right now it may be straightforward for you to have the view reference the model's state - but the model could change in the future, and then you'd be stuck updating the view, when there's really no reason the view should be impacted. And the model should never update the view's position - it should really not have any idea of any details of display. That's the job of a controller, to control your views and move them around based on model data.
Think about it this way: the view should only know how to display things or interact with user I/O, a model should only know about the business logic with data that comes in over an interface of inputs and outputs. You should be able to run a model without a view even existing, instead you should be able to just have unit test type code that feeds those inputs and outputs. So something like moving a view around is completely out of the responsibilities of a model.

Related

How to setup asynchronous image loading using VIPER artechiture?

The nature of the app is a UITableView that displays UIImages on every row as the user scrolls down the tableView. How should i load the image into the cell without breaking VIPER architecture?
--VC code--
func cellForRowAtIndexPath...... {
var cell = dequeueCellWithIdentifier.....
//Method 1
cell.image = outputInteracter.loadImage("someHttpImageLink")
//Method 2. - using a completion block
outputInteracter.loadImage(anImage -> {
cell.image = anImage
}
}
Both methods above seem to break VIP, since the presenter is not involved and no structures are passed between boundaries of V-I-P
How would you suggest getting the UIImages of the TableView to make asynchronous calls to get the images downloaded (without blocking main thread) using VIP? I can make the call pattern be like this, but I am confused on step #4:
VC --> interacterOutput.loadImage("someLink")
Interacter --> does the work to get the image, and send UIimage to presenter
Presenter --> UIImage is already in correct format for VC, so pass the information back to VC
VC --> How should i best setup the code so that the cell knows that its image is ready? I would not want to reload the whole tableView
Any help would be greatly appreciated.
The scenario you described isn't so much VIPER. In VIPER, the presenter is in the middle between the view and interactor. Your description is more closely to Clean Swift with its unidirectional flow of control from V to I to P.
Assuming your question is for Clean Swift, you first need to be clear about what the business logic is. Without knowing the details of your app, I can only assume you first ask the interactor to fetch a list of objects in JSON. Each object has a link to an image somewhere which you then have to fetch separately.
If my assumptions are correct, fetching these individual images isn't the business logic. It is simply one part of the business logic. The business logic is to fetch the list of objects in the first place.
Once the list of objects is received in JSON, your presenter can assemble a view model object to represent these objects. The image URLs can be represented simply as String instead of UIImage.
If you wait to fetch all these images before you pass the view model object back to the view controller, your UI, although not technically being blocked, will have a long wait before the user sees content in the table view. Therefore, I would simply pass the image URLs to the view controller.
The view controller can then fetch the actual images all in itself without involving the interactor or the presenter. It can use something like SDWebImage to fetch and cache the images for performance reason.
Not everything has to go through the VIP cycle. The following may help.
Think of the business logic as fetching the list of objects. Once that's done, the business logic is fulfilled. The view controller can choose to display the image URL strings, not the actual images, to the user. That's certainly one representation, although not common. But your view controller chooses to display the images as UIImages. This displaying is only internal to the view controller. It isn't really your business logic.
Your view controller can fetch the images itself. It can even asks a custom subview to do the fetching.
A subquestion in your question is about not reloading the table view if you were to fetch the images individually going through the VIP cycle. I wouldn't recommend doing this. But if your list of objects is actually just a list of images, as in a photo album collection view, this may be necessary. I would embed the image URL, the row/column data in a request object to the interactor. When an image is returned asynchronously, I would already know which row and column this image is to be displayed at. Just pass that along to the presenter then view controller. The view controller can then just reload a single cell instead of the whole table or collection view.
I hope this helps clarify VIPER, Clean Swift, VIP cycle, and what business logic is.

Is it possible to get a singleton view model in mvvmCross?

I have a view which has 2 controls on it. They all use the same viewmodel, but if controlA makes a change to the view model, then I want controlB and the view to be able to see the change that has been made. My first thought about how to do this is to make the viewmodel a singleton, but I can't work out how to do this. Any suggestions either for making the view model a singleton or for a different way to achieve the same result?
Thanks.

iOS 7 settings like DetailViewController

I have a simple project that was started from a Master/Detail template for iOS7.
I'd like to layout the detail view controller just like iOS settings. Do folks recommend using a table for that or just laying out the controls one by one?
Here is a screenshot of the effect I am looking for:
This is probably a matter of taste/opinion but I prefer tables for this kind of thing for these reasons:
You get all the nice features of tables right out of the box (efficient scrolling, cell reuse and delegate methods to handle where to push new view controllers on to the stack, etc...).
Flexible data model backed cell data. Your table view needs to be backed by some "settings" model object collection, obviously. That collection can be modified to include or exclude settings programmatically. Combine this with custom cells and you're off and rolling. This is really nice if your UI needs to change on the fly.
Code Reuse. If you have another set of "settings" you can use this data-backed table view approach and change only your data model. Doing this manually means you have a new view controller for every settings view. In your example picture, I'd bet my lunch that the 3 view controllers you see in that image are the same type of object.
The table's delegate methods are really helpful when segueing or pushing to new view controllers. Imagine having 10 settings that all took you to separate view controllers. You'd have to manually hook those transitions one by one, yuck.
Of course if you only have 1-2 settings that will never change, perhaps manual is the way to go. For my money, though, tables make sense because things like this always seem to change.

Retain View Controller when popped from Navigation Controller using ARC

I have two table views and a detail view being managed by a UINavigationController. When a row is selected on the second table, it pops to a detailed view allowing changes specific data represented by the row. I need to be able to switch between the UITableView and the UIViewController without losing any of the data that might have been changed in the UIViewControllers (button selections, text values entered in fields, etc).
Basically, once the UIViewController is presented, one should be able to switch back and forth between the table and detail view without losing any data.
The problem is, when a UIViewController is popped from the navigation controller, that memory is automatically released, and since I'm using ARC, I can't just keep a pointer to that with a retain command in the UITableView.
I know that I could manually rebuild the view each time its corresponding table row is selected, but I feel that might be a messy solution. Another option I've thought of is keeping an array of pushed UIViewControllers and checking if the selected table row corresponds with an existing value before a new one is created, but that might also get messy.
Any suggestions?
Your final wish in this back and forth of view is what you stated in your question: you want to switch between view controllers without losing any information of the actions performed in these controllers.
But if you think at how MVC pattern works, you should consider a view controller as the glue logic between the view and the model. The view is not persistent, that's why it is legitimate for ARC to get rid of the owning view controller when the view is no more needed. Instead what you should persist while your app is working is the model data only: the model data will be shared between the involved view controllers, the view controllers will be recreated each time and the corresponding views will be updated based on the model data. The only reason why the view controller should be kept alive is when its alloc-init-loadView takes too much (e.g.: the view is OpenGL backed) but in such case I would suggest you to keep a strong reference to it in the AppDelegate and ask it to refresh the content when the model data is replaced.
So basically what you should do is:
- select the table
- extract the model data associated to the table, including all information relevant for the view controller
- push the view controller; save all view modifications to the model
- when the view controller is popped, the model data will be returned only
- next time, when you push the view controller again, you will restore the model and re-init the view controller.
This approach is not complicated and gives you the possibility to structure the app in a clean way. Tomorrow you can change your view controller structure (that its view and the logic) without any impact in the communication with the other view controllers as this managed by the model passing only.
There are a couple of solutions to this, just like you suggested.
The array solution is highly inefficient because of memory issues.
The second solution you proposed is a lot more elegant. Just write your own init method in that view controller and init the view controller with data from a plist file
If I'm reading the question correctly, you've got a tableView and a detailView that are driven by the same model data. When changes to the model data are made in the detail view, you want those changes to persist.
If you update the model based on the state of the controls when the detail view is popped, then those changes will persist and the changes will be visible the next time you drill back down into the detail view.
You don't mention what form the table data takes, but let's assume it's an NSArray of NSMutableDictionaries. When you tap the row, the didSelectRowAtIndexPath: method will need to hand the dictionary from that array index to the detail view controller through a property on the detail controller. The detail view controller will update the dictionary values in the method that dismisses it.
The way to think of this is using the model-view-controller pattern. The table and detail view data is stored in the model; the views present the data; and the controllers are responsible for updating the model and navigating between views.

Where does a Datasource object belong to? Controller or Model?

I'm implementing a datasource object for an UIScrollView. Is that part of the Controller, or part of the Model? I think Controller, but not sure. It delivers the data. But the data could be in sqlite3, files, from the net. So actually I would say it's not from the Data part, since it should be flexible to from where the data comes. What do you think?
The data source for any visual control should be your controller. Your controller should get/process the data from the Model and then hand it off to the view.
I would say it is actually neither. Your UIScrollView datasource is simply formatting your data for display.
Unless you have specific actions that perform "business logic", your UIScrollView datasource participates in the View.
The Controller would include logic that modifies or processes data in any way, your scrollview simply allows the data to be displayed.
Cocoa's MVC paradigm encourages both "model controller" and "view controller" objects. The data source object falls in the view controller category; it requests model objects from the data store depending on what UI element needs them, reformats the data a bit to fit , and passes it on to the UI. Usually the same object will also handle UI events and delegate methods.