Persist different objects (types) as single object - CoreData - (Favorites example) - ios

My question is how to implement this correctly and with good design.
I would use Core Data for this.
Problem description:
Let's suppose that we have two object types (classes) in the system, Location and Event. They are retrieved from webservice, and there is no need to persist it.
Any of these two kind of objects can be added (saved) to favorites and it should be persisted locally.
Additional requirements:
show and manage favorites - let say in FavoritesViewController (I would use here NSFetchedResultController)
display (cell) of favorites is different, according to favorite type (location or event)
in Location/Event details view controller, there will be an action to add/remove to/from favorites, and the state of that action should be set according to favorites existance
in the future, it can be another object type which can be added to favorites (for example, Drink).
I have a dilemma about the best way to implement this. Should I store locations and events directly as separate entities (model objects), and somehow retrieve it in a single fetch, in order to get and manage the list of favorites. Or, maybe use an interface/protocol (for example Favorable), and create and store Favorite objects, and each object which can be added to favorite should implement favorable and will be converted to Favorite object, but in this case, it will limit favorites to only attributes that Favorite object exposes.

You should make a simple Core Data model with the two entities. It is very straight forward. Your table view would have two type of cells (with different identifiers) that display the data as needed.
You can use these to entities (subclasses of NSManagedObject) throughout your app. You should perhaps persist them anyway (so they are available if the internet goes down and allow the user to continue working with them). The favourite instances can be marked with a BOOL property.
One design consideration, though: maybe you want to create an optional relationship between Location and Event. Some events might be tied to a particular location and you will need this info as well. With Core Data this is really easy to do.

Related

CoreData mark one record as favourite (mutually exclusive)

Overview:
I have an iOS app that uses CoreData
There is an entity called Animal
It has a set of records Lion, Tiger and Elephant
I would like to mark only one of the records as favourite.
Similar entities with the same approach:
Similarly I could have other entities such as Car, Bike.
Each entity would have a set of records.
Again each entity should only have one favourite record
Reason:
App has an option to create a new document
When the new document is created, it would be populated with default values for each entity (by selecting the favourite record of each entity)
Note: Only one record can be marked as favourite at a given time
Possible models I thought of:
1. Field called isFavourite
Create a field in Animal called isFavourite.
Mark only one of the rows as isFavourite as true.
Much of the logic to maintain isFavourite is managed in code.
2. Separate entity called Favourite
Create a separate table called Favourite and have a dummy row in it.
Establish a relationship from Favourite to Animal called animal.
This will point to the favourite record.
Questions:
What is the preferred approach to tackle this problem ?
Are there any other alternatives ?
Go with option 2, maybe call it Config. If you want to ensure it is just a singleton add a attribute that is unique and can only be zero.
You can write a helper computed var returning true if the reverse relationship is non-nil.
Main advantage of option 2 is the simplicity of changing the favourite, you don't have to scan through all the items to to set them non-favourite just change it on the singleton config.
Give some thought to other parts of the app and to what you might want to do in the future.
Adding a field: Works OK but requires some code to maintain, which might be error prone. On the other hand maybe one day the app might allow multiple favorites, and this will just work with that.
Using a separate entity: Also works OK but adds a whole new entity where you'll only have a single instance. In general, if you have an entity where you only ever want one instance, you're doing it wrong. On the other hand this also works well with the potential for multiple favorites.
A third approach is to save the objectID for the favorite animal somewhere outside of Core Data, like UserDefaults. Save it, and then find the favorite by using NSManagedObjectContext's existingObject(with:) method. You can't save the NSManagedObjectID directly but you can get its uriRepresentation() and save that.
I'd probably go with #1 in most cases but it depends what else I need in the app.

How to add same object type as different tables in same realm?

I'm using realm to cache certain network data coming down which is specific to the last search. I'd also like to be able to star or pin this data to save it for future usage. The data objects are exactly the same and I can't find anything in the documentation that allows me to save them in separate tables in Realm.
The easiest way to go about doing this would be to simply create a subclass of your model object with a different name (e.g., MyDataObject and its subclass MySavedDataObject). This will create a new table in the Realm database file with the same schema and will let you distinguish between the two types of objects.
You can then create a copy of a normal object as a saved object as simply as the following:
let myNewSavedObject = MySavedDataObject(value: myDataObject)
That all being said, instead of duplicating data, I would personally recommend being a bit more efficient with the existing data set. Surely simply adding an additional boolean property to the schema named something like saved would let you simply mark objects that you wish to keep without needing a whole second table. :)

Realm over CoreData should I use NSFetchedResultController or a Dictionary?

I'm working on an app using Core Data and NSFetchedResultController but for many reasons I would like to switch it to use Realm.
I saw that there is a "Realm version" of the NSFetchedResultController on github but It wouldn't be compatible with my current code using Core Data.
The view controller is displaying a list of People from the same school, like an address book.
This list is a sublist of a people who studied in the same city.
So I was thinking to make 1 unique request to the database to retrieve the list of all people and then filter locally this list within 1 Dictionary per school [String: AnyObject] with String as Section name within the tableView and AnyObject an array of people.
first solution, make a NSFetchedResultController for each school with a predicate filtering the location. Then all delete actions etc.. are handled by the delegates -> this is not compatible with Realm
Create those dictionaries and update them for each actions... -> this works with Realm but it's very annoying to code.
Any better solution?
EDIT:
I need to clarify my request:
I'd like to write a class that inherit UITableViewController.
This class has a list of people sorted in the alphabetical order
The tableview has section with the first letter of their firstname
The tableview controller needs to handle updates of the data model (insert, update, delete)
As we might move from CoreData to Realm, I'd like to write code that is compatible with both so that I don't need to modify it again later. The only "smart" way I found to do it so far is to forget about the NSFetchedResultController and the RBQFetchedResultsController, because they are respectively linked to CoreData and Realm, and then use data structure like Dictionaries.
Just to clarify, you're creating a UITableView with multiple sections; 1 per school, and you want to sort a flat list of people in a Realm database into the table based on their school, correct?
If that Realm fetched results controller you mentioned (I'm guessing it's RBQFetchedResultsController) doesn't fit your app's architecture, then yeah, dictionaries would be the way to go, but it shouldn't hopefully be as 'manual' as you'd think.
The good thing about Realm Results objects are that they are 'live' in the sense that if a new item is added to Realm after the Results query was made, it'll be retroactively updated to include the new item. That being the case, as long as you're managing a dictionary of Results objects that each relate to fetching the people for each specific school, the only manual aspect would be managing the table sections themselves.
The only thing to be aware of is you'll need a mechanism to be notified when a new person has been added to a specific school (in order to know to refresh that section of the table view), but for now, it would be best if you did that in your own logic (Either through a callback block, or a delegate call).
On a sidenote, we're in the middle of adding a set of new APIs to make implementing native fetched results controller behaviour possible in Realm (i.e., automating the need to post a notification when a new object is added). We haven't got a proper release date confirmed yet, but it should be within the first quarter of 2016! :)

Understanding of NSCoreData and MSManagedObject subclasses

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.

How can I have multiple copies of an object that are identical update while instantiated as separate objects in different view controllers?

I'm trying to have multiple copies of a single product objects in different view controllers (i.e. you have a product in a shopping list and when you search queries web-service and returns searched products). There is a symbol on search tableviewCell if that product is in the shopping list.
I thought of two ways to do this:
Have an array in a singleton class that caches the products in a NSMutableDictionary by their id numbers and every time a products is created it check to see if there is one in its place. If so it just uses the product already there. I can have a setting in the product that states if it is on the shopping list or not.
Use core data. I tried to implement it but not sure how I can exactly do this. I was thinking of using core data so that when i update a product object it is also updated in other parts of the app using NSFetchedResultsController.
What is "standard practice" for this situation?
Let me know what you think and how you would approach this. Thanks!
You can use singleton pattern for your data manager class, which will hold your data in an array of Models (For e.g.: Product)
If you use singleton data manager (for e.g.: ProductManager) then your data (for e.g.: Product entities) would be persistent for all your class files in application life cycle mode.
Here you can find more information:
Objective C Singleton Class
http://www.galloway.me.uk/tutorials/singleton-classes/
Hope this is what you are looking for.
if the shopping list doesnt need to be written to disk, option 1 is fine. if it does need to be written to disk, you can use core data.. or use sqlite, or NSArchiver. there are a few ways of storing data.

Resources