CoreData mark one record as favourite (mutually exclusive) - ios

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.

Related

Core Data: Which record loads by default in core data if you do not specify which one?

I have a static table for settings where I want to pull some stuff from an entity in Core Data. The use case does not lend itself to a table of records as you usually see. Rather each row of the static table is really a field related to the user--as in a user profile. I have a feeling that in testing I may have created more than one record in the entity. I know there are programs that let you see the SQL lite database underneath, but my question assumes you do not have this tool and are relying just on Xcode.
My question is when you have more than one record in a Core Data entity/table, and you try to load data from the managed object context into a VC, one field into one element, what record is shown by default?
Related to this, if you don't know how many managed object or rows are in the database, is there anyway to specify which record you want since there are no auto ids as you would use in a traditional database?
The record that gets loaded from the fetch first. Depending on your sort that might be consistent or it might be random.

tableview from multiple core data entities swift

I am struggling with something I think should be basic but cannot figure out. I have two entities in core data with a one to one and one to many relationship. They are Company which can have multiple Opportunities.I want to load a table view listing the opportunities (sorted by name) with their associated companies. Can this be done by simply accessing the Opportunity entity? If so, how do I access company? The Opportunity class references it as a "Company" type and so I tried to go using dot notation through to company.companyName but it failed on that, and if I change it to simply company (of type Company) it does show .Company: and other reference data but not the simple name field I am looking for. This seems as if it should be simple but...........
This was simple and I was overlooking the ability to load the fetchedresultscontroller with the right type (in my case the Opportunity class) and then use dot notation from there. I was trying to do it with key value access which did not work. Cheers

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

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.

How can a user add a new field to a table by creating a new attribute

I'm new to Core Data and I got stuck at this part of my xCode project.
I have created a core data entity "Person" and this entity has the following attributes:
name;
age;
birthday;
address;
and this attributes are getting displayed in a tableview. So far so good.
My problem is that I want the table to have an "Add Field" or "Add Row" cell so when the user wants to add more information in addition to these already created attributes he just clicks the cell and chooses the field name and type.
For example if he wants the person's "phone number" in the detail view of the table he names the new field "phone number" and chooses its type "number". Then he has an extra field where he can add the person's phone number.
How can I do this in core data? Is there a way for a user to manually add a new attribute to an entity and choosing its format? What is the best approach? Thanks.
You can't do exactly what you want with Core Data. Core Data can't change structure except if you make a new version of your design, but you do that in xcode.
But you can easily add another table called f.ex. information, which links to the person single connection and has the person linking back many to the information table.
This way, you can add as many fields and values as you want, of course all the extra fields you add would follow the same person, so if you want to use cellPhone field, you must add that to all.
I would recommend that you use direct SQL, and don't use Core Data. Core Data is not a database, it is an object store, and when you get better at iOS development, you will understand the difference, it is much bigger than you might think at first.
There is an excellent high level library for SQLite, called FMDB, you can find it on github here : https://github.com/ccgus/fmdb
Here you can do direct SQL queries like "Alter Table" and more on the fly, though what you are after isn't very simple, it could be real fun project to do.
Good luck with this.
I don't think this is directly possible in Core Data because its purpose is object persistence and you can't add new properties to objects dynamically. It could be faked to some degree using a to-many relationship to an "extra property" entity that had name, value (as string), and data type fields.
I believe your best option would be using SQLite in order to modify the table structure on the fly. (http://www.sqlite.org/lang_altertable.html)
My last company did something like this, but its not trivial. I don't have access to the code so this is more or less going to be from memory.
you provide transformable property in your entity (which will be a dictionary)
the model object has to provide the getter and setter for this that in turn drive the primitive methods to set/get an attribute
you provide a getter/setter along the lines of -objectForKey and -setObject forKey, which read and write values
when you are told to 'fault', you update the dictionary in the entity
In summary, maintain a dictionary of key value pairs. Perhaps you maintain a shadow dictionary that gets initialized and updated as needed. Its been around 4 years since I last saw this code so a little fuzzy on it. But you should get the idea. It was like magic - you can arbitrarily set any key/value pair (assuming string keys and NSCoding compliant values), and can always ask for the keys by asking the dictionary for its current set of keys.

duplicate NSManagedObject

I am using CoreData in my app and i have a set of "Card" entities. A player can have more than one of the same card in his deck (it is still the same card pulled from the database but added two times to an array).
My problem occurs when I want to modify an aspect of one of the duplicate cards. They are all subclassed NSManagedObjects which have some custom properties on them (which are not saved onto the database). For example when I set one of the custom properties on one card in the array it is also changed in the other same card in the array because the entityForName:inManagedObjectContext: returns the same object and does not load a new one.
Basically what I need is that each time entityForName:inManagedObjectContext: is called I get a new instance of the same entity so that when I modify a custom property in one it is not also modified in the other. I have already tried using [entity copy] if the entity has already been created but it does not work.
Thank you in advance for your help!
Core Data is a persistent store, not a database. So it's reason detre is ensuring that you get exactly the same object out, no matter how many times you ask for it. Those aren't snapshots from the database as they might be if you wrote some custom SQL code, those are the actual live objects.
With that in mind, what you need to do is either configure your Core Data schema to match your logical schema — I guess you'd have, say, CardInstance, with a one-to-many relationship with Card, and you'd create CardInstances for when you pulled a card from the deck — or write some code to read from a fetched Card into a snapshot object, exactly as if you were working manually with SQL or whatever.

Resources