Discrepancies Between Core Data Editor and NSManagedObjectSublcass - ios

How are discrepancies between the Core Data Editor and the custom NSManagedObject subclass handled by Xcode?
For instance, let's say in the editor I have and Entity called Person with attributes firstName and age. I then create an NSManagedObject subclass of Person from the editor and in the header of the subclass I add the attribute lastName but I don't update the editor with this new attribute.

Depends somewhat on exactly how you define the property, but usually it will be treated like a transient property, so its value will not be set when the object is retrieved from the store unless you write some custom code to set it, nor will Core Data make any attempt to save it to the store. Also you won't be able to use the property in any fetch or sort predicate that results in core data generating sqlite SQL calls.

Related

Remove or Add an attribute to CoreData at runtime programmatically

I have to create and remove attributes based on an api response in Objective C.
For example, Now my api response contains fields "facebook", "whatsapp" and "viber". But in future the reponse can add "youtube". Based on this response, I have to remove all the attributes and values of an entity "Social", and create Four attributes now and set values.
How to do that programmatically? Because the default *.xcdatamodeld file cant help me here, right?
Note: My project is in objective C.
The data model is mutable when the app starts-- you can completely build the model in code, and not use the model editor, for example. But as soon as you load a persistent store file, you must treat the model as fixed. Any changes after loading a persistent store will cause crashes. That means any changes would have to happen before calling either loadPersistentStores(completionHandler:) or addPersistentStore(with:completionHandler:).
Alexander's suggestion of optional attributes is a good one. If you need the model to be more dynamic, you would need to create a new related entity which would store the service name plus whatever information you need to save about the service. If you did this, your Social entity would have a to-many relationship to a new entity called something like Service. Service would have a string property called name that would have values like twitter, facebook, youtube, etc. It would also have whatever other attributes you need to save about the service.
You can create all 4 fields in advance and just make them optional and fill them depending on the server response. But you cannot add new attributes in runtime. Your *.xcdatamodeld file compiles into *.momd and it contains all the data to create tables in the DB since Core Data by default works with SQLite under the hood and it's a relational database management system.
To make attributes optional you should check that.
And then newly created objects contain nil as default values of object properties. So, in your case your "youtube" property of Social object will be just nil.

Core Data lightweight migration - do existing entities have new attributes added to them?

I have a Core Data managed object model all set up and working in an iOS app, and I'm using NSManagedObject subclasses which are instantiated using [[MyEntityClass alloc] initWithEntity:description insertIntoManagedObjectContext:context];
I have been reading some tutorials on Core Data migrations to prepare for possible future updates to the app. For the changes I currently envisage for this particular case, I am confident that lightweight migration will be sufficient. I understand that lightweight migration maps the data from the old data model to the new version. But there is one thing I'm not clear in. If the persistent store contains NSManagedObject subclass instances which were created from before the migration, will these objects be modified along with the model to allow them to use the attributes added in the migration?
I'll give an example to make sure I'm being clear about what I'm asking. Lets say I have an entity called, to use the classic example, Person. Person has the following attributes:
firstname
lastname
I create an instance of Person called aPerson and this is inserted into the persistent store. I can access aPerson's attributes using aPerson.firstname and aPerson.lastname.
Now I add a dateofbirth attribute to the managed object model, so the Person entity contains the following attributes:
firstname
lastname
dateofbirth
Now, what happens if I retrieve aPerson from the persistent store and try to access aPerson.dateofbirth? Will I get an unrecognised selector error because aPerson does not contain the dateofbirth attribute due to being created before the addition of that attribute? Or will the lightweight migration add the dateofbirth attribute and the accessor methods to all instances of Person already in the persistent store?
If you add an attribute to a new model version, the attribute must either be optional or you must specify a default value. Otherwise the persistent store saved with the old model would not validate with the new model.
In your example, it does not make sense to specify a default dateofbirth, so you would make that attribute optional and cope with it sometimes not being present.
I can’t find explicit documentation on this. You should test migrations very thoroughly.

How to use NSManaged object class using NSObject class

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.

Default value to core data attributes (column) for iOS programmatically

Current Approach
I set the default value of the attribute directly to the data model file using the inspector.
Problem
I have enum for the values a particular attribute can take.
I am worried maintaining them at a later stage might be difficult.
Suppose if I decide to change the enum values, then I would have to manually go the inspector and change it.
Since I have quite a number of attributes based on enum values, it becomes difficult.
Question
How can I add default values to core data attributes programmatically ?
Is there any alternative to do this, so that maintenance would be easier ?
Everything you can do graphically in the Core Data model editor you can do using the classes Core Data provides for creating/introspecting a managed object model. For this use case, you can use NSEntityDescription to look up an entity, its properties or propertiesByName accessors to find the NSAttributeDescription for the attribute you're interested, and setDefaultValue: to do the same thing the Core Data model editor does.
You might find this the most appropriate way to do what you're looking for. Or, as #DimitryShevchenko notes, you can initialize values in your NSManagedObject subclass' awakeFromInsert method -- which way you choose might depend on your workflow or other requirements of your application.
You can subclass your NSManagedObject and set default values in awakeFromInsert
Related docs (see Object Life-Cycle)

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.

Resources