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
Related
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?
I am learning a bit on NSCoreData and before introducing it some existing projects I have, I would like to validate my good understanding of the core principles.
From what I have understood, NSCoreData make it easier to manage local storage of object (+retrieval after that) by subclassing our Model class from NSManagedObject rather than from NSObject.
Right ?
I have a few questions then. Let's consider I am building a real estate application with as core model object the class Property that can represent an appartment, a house, and all related information. Currently it is managed in my app as a subclass of NSObject.
1) I retrieve the properties from the server through a search query, and have written a initWithJson : method to populate each instance.
Now if I subclass Property from NSManagedObject, I will create my instances by using
+(id)insertNewObjectForEntityForName:(NSString *)entityName
inManagedObjectContext:(NSManagedObjectContext *)context
and I will be still be able to add a populateWithJson: to my class to fill in the properties.
Then I will create a lot of Property instances in the current managedObjectContext, and if I do a save, they will be stored at the physical layer.
If I call again the same webservice, and retrieve the same JSON content, I will recreate the identical managed objects.
How to avoid redundancy with the [managedObjectContext save:&error] call and not to store physically several time the representation of a single real life property ?
2) Let's say I want to store physically only some properties, for instance only the one the user want to have as favorites.
[managedObjectContext save:&error] will save all created / modified / deleted managed objects from the context to the physical layer, and not only the one I want.
How to achieve that ?
Am I supposed to declare another context (managedObjectContext2), move the instance I want to store in that context, and do the save in that one ?
(I mean, I will have a context just to manipulate the object, create instances from the JSON and represents them in UI ... and a second one to actually do the storage)
Or am I supposed to stores all the objects, and add a isFavorite BOOL property , and then fetching using a predicate on that property ?
3) The app has a common navigation pattern : the UITableView lists Properties instance with the minimum information required, and going on a detail view call a webservice to request more information on a specific Property instance (images, full text description).
Is it a good practice for instance to call the webservice only if the property.fullDescription is nil, and then update the object and store it locally with all detailed information, and the next time only to fetch it locally with a predicate on the property.id ?
What about object that might be updated server-side after they have been created?
Thanks for your lights
1) Retrieve the server data into a temporary form (array of dictionaries?), then for each possible property in the array, check to see if you already have an object in Core Data that matches. If you do, either ignore it or update any changed attributes; if not, create a Property object.
2) Decide which things you want to persist in order to support your app's functions. There's no point in creating a managed object for something you don't want to save. Note, though, that Core Data supports sub-classes if you want both Property and FavoriteProperty.
3) Entirely up to your "business rules"…. How often do you need local data to be updated? The only technical consideration might be the guideline to not keep large files locally that can be re-created on demand.
I have NSObject class name TrackInfo which contains tracks info like name , artist name,thumb image etc.
I use this class as downloading data and save information to that class after parsing data.
Now I have another tab in which, I have to show some data. This is same kind of data like trackInfo. But when app is in OFFLINE, I have to make NSManagedObject. It is same as trackinfo.
Can I use NSObject class instead of NSManagedObject or Vice-Versa ?
What I basically wants to do is, I have to display track info from one class either Trackinfo (NSObject class) or NSManagedObjectClass which is used to save data when app is in offline.
Short answer is yes, you can. How? You can find a useful discussion Organising Core Data for iOS.
The long answer can be grabbed within the documentation.
NSManagedObject is a generic class that implements all the basic
behavior required of a Core Data model object. It is not possible to
use instances of direct subclasses of NSObject (or any other class not
inheriting from NSManagedObject) with a managed object context. You
may create custom subclasses of NSManagedObject, although this is not
always required. If no custom logic is needed, a complete object graph
can be formed with NSManagedObject instances.
A managed object is associated with an entity description (an instance
of NSEntityDescription) that provides metadata about the object
(including the name of the entity that the object represents and the
names of its attributes and relationships) and with a managed object
context that tracks changes to the object graph. It is important that
a managed object is properly configured for use with Core Data. If you
instantiate a managed object directly, you must call the designated
initializer (initWithEntity:insertIntoManagedObjectContext:).
About your question, it depends on what you need to achieve. If your goal is to perform a sync mechanism between your device and the server, you should set up 1) a model with a TrackInfo entity 2) a Core Data stack that relies on a persistent store like SQLite. Then you should modify TrackInfo to take into account modifications to that entity. For example, a dirty flag property (0 or 1) or a timestamp. When you do a modification on your TrackInfo you update that property. When the connection is restored you need to query against that property and sync with the server. If you choose the timestamp, the server should say what is the latest timestamp to query against.
I have the following datamodel to manage measurements (heart rate and skin response)
When I'm acquiring a new measurement it's going to be an entity of "MinuteStress"
Now I want to programmatically check if a corresponding day and month entity exist and if not create one automatically and add my measurement to their average.
My first question would be: Where is the right place to check for the super entities? Is it a good idea to do this in the NSManagedObjectSubclass of "MinuteStress" or is it better to do so after I create the entity in my viewcontroller?
My second question would be if there is a smart way to create super entities from a sub entity?
In theory you can do that in the awakeFromInsert method of your NSManagedObject subclass, but that's a Bad Idea (tm) because you can trigger other Core Data events... see the "special considerations" section under awakeFromInsert in the Apple Docs for more info.
You'd be better off to query for the superclasses in the view controller and create them if needed, then create the MinuteStress instance.
You might also want to write some convenience methods for creating related child objects (like -(DayStress *) createDayStress] on MonthStress for example) where you create a child object and automatically set its parent reference (and any initialization values) before returning it. It makes the code flow in the view controller much nicer IMO.
I built a Core data model with different entities for my database, on my iPad app. I do want to access these attributes (and fill the dBase) from different viewControllers. For instance, there are UITextFields in viewController A, and another UITextField in viewController. I'd like the seized information to fill different attributes from my Core Data entity...
Is that possible? What is the best practice to do so?
My problems :
I declare the objects with type "entity" in viewController A
I fill different attributes of this entity with the seized text, also in viewController A
I store the objects (same type as my entity) in a NSMutableArray in viewController A
I use different methods to save and retrieve this NSMutableArray in viewController A
Any help or advice would be appreciated! :-)
Here comes the power of MVC. Make a class (model as of M of MVC) which is responsible for you data manipulation - fetching, updating, deleting, etc... Make this class either singleton or add a property in the AppDelegate and take in every UIViewController you need it. Collect all the data from the view controllers somewhere else - eg. some dictionary or something, then call a method of your data class that will insert the data, when ready... Good design always leads to less problems and difficulties with implementation and also makes further changes to the UI easy and fast...