I wonder 4 questions about the data model when creating iOS apps:
Do you create a class called DataModel and inside there we find arrays and objects that belong to the data model that is instantiated by every model? Or do you create a data model that is a singleton and has the app state? I guess singleton is not a good idea because is difficult to test.
Where do you write your networking code and mapping code (converting json files into data model objects)? I guess it should be an object inside the data model.
I understand the model encapsulates app state, for that reasonI I guess if we have a table in controller A and the detail in controller B (using a navigation controller), maybe we have to create an instance of the data model that holds ‘selectedStudent’ and then once the B controller is pushed, it uses the model to know what student was selected.
That’s what I understand from this image:
http://naikom.ru/img/2012/ios2/8.jpg
However from this image;
https://littlehales.files.wordpress.com/2012/01/mvc2.jpg
I see that there are several models and controllers communicate each other, so in my example, using prepareForSegue I could pass the selectedStudent to the other controller. If we do that, then the controller is encapsulating state, rather than the model.
Can you explain to me how I should do that? Or how do large apps do this?
According to this diagram:
http://i.stack.imgur.com/Psi8i.png
In order to send information from the data model to the controller we have to use NSNotificationCenter or KVO.
I know the problem of delegates is that they are just a 1-to-1 relationship, so probably not good idea. What about blocks or creating your own observer using a protocol and addObserver/removeObserver (using an array or a set)? Do you really use for this NSNotificationCenter or KVO in the data model?
Related
I'm Use structures by default when possible,
what's the best practice to update the original struct instance a copy of it was passed to another variable.
let's say I have a Post struct
struct Post {
let title: String
let likes: Int
let viewsCount:Int
var comments:[Comment]
}
and we have a simple Master-Details Screens
when pushing the details screen we are copying the post to the details scene, and there the data may be changed as likes increments, added comments and so on,
so when pop This ViewController, to the new data model to update the original model in the Master ViewController.
what are the possible solution and the best practices for it?
assuming we are using MVC or MVP
You could create a common shared model class that is responsible for holding the Post data and that both view controllers could use and observe.
This really has nothing to do with structs; it is simply the usual issue of passing data into a view controller on creation and passing data back from that view controller on destruction. It happens that in your case you are positing that this is the "same" data — i.e. you pass a Post to the detail view controller and you pass a Post back from the detail view controller — but that is just a contingent fact.
So, to answer the question as formulated, you would use any of the usual techniques. The detail view controller would need to pass the modified Post back to the master view controller. It could use a Notification or (more directly) you could use the standard protocol-and-delegate architecture.
On the other hand, if Post is the basis of your app's data, it would not be unreasonable to argue that the premise itself is flawed: this should have been a class all along, not a struct, exactly so that the data can be maintained in a central place and references to it can be maintained in different places.
Indeed, if things are more complex, you might have the app's data (including the Post) live in some third location off in model-data-space, and have all view controllers send a notification up to the data when they change it and have the data send a notification down to all view controllers in response (that is what Ralf Ebert's answer quite reasonably suggests). That sort of thing is a lot easier nowadays because (in iOS 13) we have observable objects and the Combine framework.
I would create helper functions and make them mutating. e.g.
mutating func incrementLikes() {
likes += 1
}
Make sure your properties are var.
Ideally classes are best for the role you described as object maintain identity.
Each post has an identity.
According to apple docs "use classes when you need to control the identity of the data you're modeling"
When you share a class instance across your app, changes you make to that instance are visible to every part of your code that holds a reference to that instance. Use classes when you need your instances to have this kind of identity.
Classes vs strut
I would like to know how can we manage our domain Model and NSManagedObject Model. My scenario is I have to show last 5 comments from coredata which I fetch from coredata manager class, and it returns 5 objects of Comments (:NSManagedObject) object. now I want to to fetch next n number of comments from our server API and will parse them into my domain model object Comments( inherited from NSObject).
Now I have two types of object which logically represents the same object. I want to know best practice/design pattern, how we should handle/implement this.
One obvious solution is to loop through NSManagedObject Model and populate 5 new models of my domain object derived from NSObject and then continue to fetch these objects from my APIManager class. But I want to know the best way if there it is any.
First of all, CoreData is not thread safe, so don’t use those comments objects into the controllers or the views. Isolate core data in a separate layer and transform these objects into a view model or some other form of immutable struct for the view.
Second, you can use a nsfetched result controller in a “provider” class to keep you informed automatically of what are the last 5 comments. A delegate can inform your view of when this provider data change.
You can refresh your server data in background with your api ma manager and when you get the data back, store them in coredata. If you used a nsfetched result controller, you won’t need to do anything else as coredata will automatically notify the object you setup to return you comments
In my Swift app, I'm trying to follow a more Protocol-Oriented Programming and Value-Oriented Programming approach, keeping core model objects as structs with a thin layer of managing class objects.
In callbacks and completion handlers, one often needs to refer back to a source model object. e.g. When a video finishes loading, you want to take some action on the model object (a struct) that contains the video.
In these situations, what's the best practice way to get a "reference" back to the model object, if it's a struct? (Assume the managing class contains an Array of model structs.)
Pass back a primary identifier (a property value) for the struct and search for it?
Some other way of identifying which struct is the one to use?
Or is this fighting against OOP too hard, and really the model object should be a class, like we've traditionally done, since it has an "identity"?
I have a problem to understand how to properly download data from a database to my model object according to MVC architecture in my app.
Here is how the app looks like:
/ NavigationController -> ViewController -> ...
TabBarController - NavigationController -> ViewController -> ...
\ NavigationController -> ViewController -> ...
So TabBarController is initial controller with 3 tabs. Under each tab there is a chain of UIViewController embedded in a NavigationController. Each View controlled by particular UIViewController is displaying data from database. These data are updated quite often so I need to download them from database periodically.
Then I have a model object. In my app I have only this one model object so all UIViewController have access to the same model object (I know each UIViewController should have its own model object but I have reasons to do that in this way).
As I understand MVC, the communication should be like this:
when a View must be updated, UIViewController sends a request for data to a model object
model object gets the data from a source
when the data are updated, model object sends information to a UIViewController
UIViewController updates data from a model object to a View
This should be OK. But I am not sure where should be placed a DatabaseController which connects to a database and sends requests to it. This should be separated controller and model object must have a reference to it because he needs to tell him that he needs update its data.
I have found some blog with information that the DatabaseController should be created inside the model object and separated from model object code using a category. My opinion is that this is bad idea because it breakes MVC architecture.
What do you think? What is the best solution for placing DatabaseController in the app? Should I put it into the object model or outside...
I've never used Objective-C before, but in general OOP, the code to access the DB should definitely be placed in a single, separate place - among other things, this makes it mush easier to maintain and modify the code to access the DB in the future, and makes code clearer in general.
A well-known and widely used approach is the Data Access Object (DAO) pattern, which allows you to abstract the persistence details of your application from the rest of the logic.
The Repository pattern is also used very often for this purpose.
In your case, if you have a model class called Thing, you'd create a ThingDAO, with methods such as getAllThings(), getThingById(id), updateThing(thing), deleteThing(id), etc.
Then you can call this object from your Controller, or better in my opinion, from your model class(es).
You may think that, as we add another layer, "it breakes MVC architecture" - in my opinion, actually the DAO layer is a part of the model. I think your concept of model is probably not quite right - bear in mind that the model is not one class, but a group of (potentially thousands of) classes. In a big app, your model would contain things like Entities, DAOs, EventListeners, Handlers, Managers, Commands, Transformers, Helpers, and many other things...
Data access, and more, like business logic should be part of the model, and I'll try to explain why:
putting more and more of the application logic into the model component leads to the fat models, skinny controllers paradigm
fat model, skinny paradigm leads to unit-testable code, as controllers are not very suitable for unit testing
this approach also increases the reusability of your components, as it's unlikely you'll reuse controllers (most of the controllers are application-targeted)
Of course this applies to MVC, however as this pattern is heavily used in the iOS development, it makes sense to primary focus on it.
My suggestion would be to move towards MVOC architecture where O represents Others. Others would be a layer that does not fit in either of M, V, or C. Here O would be your network layer. A singleton object that your controller calls to fetch data and gets a filled model object in return.
I have a data controller class used within my app that handles parsing xml and a few other operations vital to my app. What I want to be able to do is have the data that it parses store in an array that can be accessed in multiple views of my app. Right now, each view creates its own instance of the data controller class and so the array that the data is stored in is specific to that view controller. Is there a way to still create individual instances of the data controller class for each view controller, but the data is stored in the array where all views can access it? I have tried to store in NSUserDefaults but that doesn't seem the most effective way. Each view controller needs to have its own instance of the data controller class because I utilize delegate methods that are used in each of the view controllers. I hope this makes sense.
You have two ways to implement this (ok, maybe more than two but those are most common):
Store array in application delegate and acces it as property.
Create singleton object who gonna hold array (and other possible data/methods).