Save multiple values per key in CoreData - ios

I'm currently looking into CoreData and need to save multiple values per key. In my case I just need to save a couple of strings, max 9, for a single Key in CoreData.
Specifically, I want to save players for a game. My game object already contains relationship objects to these players, but I also want to save the Player names as records on the game object itself, as players can be deleted by my users and I want my game objects to be immune for that.
I know in Cloudkit you can set the value of a certain key to e.g. "set of strings", and this can be done in CoreData relationships to when creating a one-to-many relationship. I was wondering if there is a by-the-book way to do this in regular CoreData key-value pairs as well.

It's easier to think about CoreData as objects rather than low-level data storage. It's not really designed as a key/value system (except in the sense that any object's properties can be thought of as a dictionary).
For the example you give, it might be more in keeping with CoreData's object persistence style to flag deleted players as unavailable rather than removing them, so that your history remains intact.

You could use an attribute of type Transformable to store your set. NSArray and NSSet conform to NSCoding so CoreData can take care of all data transforming, archiving and unarchiving for you.

Related

Core data FIFO? (first in first out)

Im sitting with this issue bugging me. I have core data working fine, but when it fetches, in my case, the users, they come back in different orders. Normally would use the standard unique identifier, but core data doesn't have this. So....
Do I manually create an ID entity_property and assign it incrementally, or is the "object id" being made in incremental order; incremented maybe by 1, or just random IDs? hence making me able to use object id.
My goal is to get my fetched array in the same order the users was inserted.
Thanks
You'll need your own technique for generating the unique ID. Run that code in your NSManagedObject subclass's -awakeFromInsert, which is called once, when the object is inserted into the datastore. You can add a timestamp, or the value of an incrementing counter.
There's no built-in support for an autoincrement ID. You'll need a class variable, and increment that yourself in -awakeFromInsert. You'll also have to persist that value across launches, either as its own Entity or within the persistent store's metadata.
You might benefit from using an ordered relationship, if those users have a one-to-many relationship with some other entity.
The NSManagedObjectID is unique within the store, but will change when the NSManagedObjectContext is saved (and the NSMOID goes from temporary to permanent). No promises are made about its sequence or pattern of construction. And it can change during a managed object model migration. So don't depend on it for anything you need to control.
core data does not return ORDERED data. so, if your data is "string" or "date" type then you can simply sort your data by ascending/descending after fetching from code-data.

Learning Core Data. Entities, Adding and Loading

So, I'm trying to use Core Data to save instances of a "Screenshot" class, which consist of:
NSString *note;
NSData *screenshot;
NSData *thumbnailOfScreenshot;
NSTimeInterval date;
In my Core Data file, i have two entities because i want to fetch the large images only when necessary, and only 1 at a time (it is to be used in a UITableView).
Entity 1 is called Screenshot and consists of the 4 attributes above, whereas the *screenshot is transient. This entity also has a to one relationship with entity 2(an int called index).
Entity 2 only has 1 attribute which is a Binary data field for the Large images. Also a to one relationship with entity 1.
So, my first question: Is this remotely close to being correct? I'm a little unsure if i even need the Transient attribute "screenshot", in entity 1. And i am also confused if i need to create a new class for entity 2, which seems abit odd, since it will just contain the images.
For now, I'm only trying to add and load instances to and from the DB.
Here is how i (think) i add an instance to the DB, but i am not sure it actually puts it in the DB right away?:
Screenshot *s = [NSEntityDescription insertNewObjectForEntityForName:#"Screenshot" inManagedObjectContext:context];
I am in over my head, so any help will be appreciated. I have read several guides, but none was targeting something similar to this.
Transient properties are not saved to Core Data (they are neither retrieved nor saved out from the backing store). They are most often useful for calculating some sort of property based on stored properties (e.g. I use them for queries based on the first letter of a person's last name -- I'm storing the full last name, but the firstLetterOfLastName is a transient property -- but one that I can order results on since Core Data knows about it).
If I'm understanding your model correctly, you likely want no transient properties at all.
I also don't think you need an entirely new model for your "large images". You can instruct Core Data to optimize it's backing store for large binary attributes by turning on "Store in External Record File". You'll find this in the Data Model Inspector pane underneath where Transient and Optional are set. This will keep the actual backing DB snappy, but allow Core Data to retrieve these large binary attributes and you may still work with them seemlessly with a Core Data NSManagedObject instance.
Also, in general, do not relate items by an "index" value of some other stored Core Data object. There's plenty of reasons to do so, but in general, this is what Core Data relationships are for. If "Movie" has multiple "Screenshots", for e.g, you would have a relationship on a Movie instance called "screenshots" that you simply add each screenshot to (it's effectively an NSMutableSet as far as you care).
Core Data is an object graph, not a relational database. If you add the same object instance to two relationships on different owner-object instances, you aren't duplicating the child-object -- Core Data does all the work to interrelate them for you (assuming your models are setup in a good way).
I'd rethink this. I think a single entity is enough for this. I'd either add a BOOL value named 'large' and do a fetch when "large = NO" to get the small images. Alternatively, if you want more control, add a 'pixels' or 'megapixels' field which describes the size of the image. Then you can fetch where 'pixels > 3000000' for instance.
If you have a special relationship between two images (i.e. one image is a thumbnail of another), I'd just add a relationship to another Screenshot entity.
Alternatively, you could also make one Entity the "Parent Entity" of the other (see the Data Model inspector when you have an entity selected).
You're on the right track. Keep thinking about how you want to use your entities. This should help you describe the relationships better. Quite often I write the code that uses the entities before I define them in a data model. This lets me end up with cleaner interfaces and less overlap between entities.

How to store other NSManagedObjects as property of a NSManagedObject

I am new to iOS programming and I'm doing up a simple function of an iOS application. Currently, I've created an entity called Players, and I'd like the entity to have a property, in which it stores other NSManagedObject like an array.
This is because I want a player to be able to have friends in the game and this is the way I've thought of; I could just access a player's friend's list via
[playername friendList]
May I know if this is the way to do so? Because for an entity's attribute type, I couldn't use NSMutableArray or NSArray as its type. If it is, may I know how I can store it? If not, is there a better way to achieve that?
This is the purpose of relationships in the Core Data model. Add a relationship between the two entities (and an inverse) and add the managed objects to that relationship.
See this section of the Core Data guide.
You need to create a relationship between the models, which are represented with NSSet (or NSOrderedSet, by checking "ordered", if the order is important.)
Ordered Sets are similar to arrays, except all the objects are distinct (no duplicates).

CoreData object modeling with multiple timeframes for weather data

I do have some JSON file http://jsonblob.com/530664b3e4b0237f7f82bdfa I am pulling from forecast.io.
I am little confused how I should be creating my CoreData entities and relationships.
In below setup, I made my Location entity as the parent entity and created a separate entity for Currently, Minutely, Hourly, Daily. However I have decided it's best to hold all the information regarding the weather data in one entity, so I created a Data table for that purpose and tied it to Daily and Currently in the image below.
Before going further, I paused and would like to get a second opinion on it. Is this a valid way of going forward with this?
EDIT: Based on Wain's response I changed my model to this
Currently Minutely and Hourly add little value as they don't have any attributes or relationships. It's also generally easier to add a type attribute rather than having a number of sub entities because you can easily filter the type using a predicate while doing a fetch. If you're going to add more in the future then there could be a case for keeping sub entities.
Once the entities are trimmed down then you only have a Location and Data with a relationship. You should make that relationship bi-directional so that Core Data can manage the data store contents better. (this applies to all relationships, even if you keep the sub entities you already have).
Other than that, fine :-)

Will Core Data populate inverse relationships when setting an NSSet relationship directly?

By example:
I have an entity User, and an entity Device.
User have a To Many relationship toward Device, called devices.
Device has the inverse of this relationship called user.
Now I collect, persist a bulk of devices from e.g. a network service, hydrate them into an NSSet, then I bound them to a particular user, so I do:
NSSet *collectedDevices = [API getSomeDevices];
someUser.devices = collectedDevices;
Will Core Data populate the inverse user relationship for each Device for me? Does it observe the setters for relationships?
Background:
I'm aware of the Core Data setters for setting collections, but I want to avoid using them. I'm actually reconstructing Core Data entities from JSON representations with KVC without hardcoded attributes, relationships, just enumerating their entity descriptions, and set matching values.
Yes, Core Data will set the inverse relationships whether you use properties or KVC or the Core Data specific methods such as -setPrimitiveValue:forKey:.
However, when it sets that inverse can be slightly variable. It can set it immediately in some situations and in others it may wait until the end of the run loop to set the inverse. As long as all of the objects being related are created against the same NSManagedObjectContext then the referential integrity will be maintained by Core Data.

Resources