Core-data transformable attribute not allocated by default? - ios

I have a core data model with a Transformable attribute called location. However, when I create a new entity with initWithEntity:insertIntoManagedObjectContext:, location is nil.
Is that the expected behavior? I was expecting all the memory for a field in an entity to be allocated upfront. If this is the expected behavior, what is the recommended way to work around this? Is allocating memory for location in awakeFromInsert a good idea?

Yes, that is expected. If you haven't given the entity any data how would it know what size to allocate. Even then, what would it do with that allocation because it isn't a real object and you can't really convert it into one. You should expect the property to hold nil if there is nothing there. You do no need to and should not want to fill it with some default empty allocation.
If you have a default object that you want to set then that's a different matter. Then awakeFromInsert could be a good option. The question is whether the default object should be saved into the store (and therefore be searchable). If not you might want to implement a custom accessor method to return your default object if the stored value is nil.

Related

Turn NSManagedObject into a partial fault where some fields are nil and some not

Apple describes faults as partially materialised futures which is very similar to the term partially materialised views used in several databases. Word partial means for me that some field of this object are initialised (realised) and some not. But Apple describes faults as:
A managed object fault is an instance of the appropriate class, but its persistent variables are not yet initialized.
Are there any way to partially realise a fault? E.g. I have object with 10 field and I want a partial object with only two fields realised while the whole object is still a fault (hence all other fields are still nil). I'm not talking about propertiesToFetch of NSFetchRequest here but about so called partial faults.
Because currently when fault is fired all properties are realised. Here is a quote from the docs:
If you access a property on the Department object — its name, for example — the fault fires and Core Data executes a fetch for you to retrieve all of the object's attributes
How can I customise fault realisation?
I don't believe that there is anyway to do this. When core data loads a managedObject it loads everything. You can see in NSMangedObject's interface that it has a single property of isFault which is either true of false.
If you have a property that is very large (a blob of data for example) and don't want to load it unless it is needed, then I would suggest storing it as a separate entity with a relationship. This way it will only be loaded (faulted) when you request the property.

iOS Realm object by reference or duplicate objects

I am using realm and I am not sure about this.
I have two option to do in Post. One is to save entire owner object and another is to save only user object ID. If I save entire object, is it object by reference? I don't want to increase database size.
The reason why I want to store entire object is that it is easy to access. It is like Post.User.email. I don't need to query. I read through realm though. https://realm.io/docs/objc/latest/
Thanks in advance.
No need to go by ID. In Realm, when you add a property of another RealmObject type, that will store the reference, not the entire object. So it will not take more space on disk than what you are expecting.
I am not sure if your diagram reflects your actual types, but note that when using collections, you want them to be of type RealmList<>, not Array<> (I am assuming you are writing C# as you referred to the Xamarin docs).

How to write changes from one ManagedObject to similar ManagedObjects

I am new with Core Data and have a problem which sounds trivial to solve (at least thinking in SQL) but I can't get my head around that with Core Data.
What I'm trying to do is the following: I have a fetched ManagedObject, do some changes and save it again. This ManagedObject has an attribute id. I want to write the changes I made to this ManagedObject to all the ManagedObjects with the same id.
I was thinking to overwrite willSave: and fetching the other ManagedObjects with the same id there but this won't work because I would encounter an infinite loop there.
Can somebody give me a hint on how to progress from here? Thanks in advance
You could make willSave work, but it isn't going to be a nice bit of code to ignore all of the invalid triggers.
It's better to have a class which manages this functionality, pass in the new data value and the attribute id and allow it to do the fetch and update all of the fetched objects (and trigger the save).
I would, indeed, try to find some better way to deal with it, because actually you should't think of Core Data as of SQL with its triggers.
But actually you can indeed use willSave method and avoid infinite loop. See
NSManagedObject Class Reference willSave method
If you change property values using primitive accessors, you avoid the possibility of infinite recursion, but Core Data will not notice the change you make.
So basically in your willSave method you'll need to call some fetchRequest to get all instances of the same Entity, then loop through them and update using primitive accessor: setPrimitiveValue:forKey:
Also I would advice to verify objects in loop whether they are removed (-isDeleted) and, probably, whether that object is not your current one (by comparing managedObjectIDs)

iOS: update a field in model any time managed object model gets modified

I have a "last updated" field on my model. Any time a managed object model gets changed, I'd like that field to get updated. Is there any way I can have this happen automatically? Or do I need to just update that field manually when I make the other modifications?
"Is there any way I can have this happen automatically?"
No. Core Data is not a database, it's an API for abstract object graph management. It has no concept of uniqueness, auto-incrementing values, etc.
"Or do I need to just update that field manually when I make the other modifications?"
Correct, for example having a lastModified property that your application sets with each change.
You could KVO all keys in your entity but maybe this is not necessary. I would suggest you only update the lastUpdated property when you actually save the object because before that you could still just throw away the changes (either on purpose or e.g. because the app terminates).
Therefore, you can simply override willSave. This is specifically designed for this kind of situation (it mentions a "last-modified" attribute), but note the caveats mentioned in the documentation
If you want to update a persistent property value, you should typically test for equality of any new value with the existing value before making a change. If you change property values using standard accessor methods, Core Data will observe the resultant change notification and so invoke willSave again before saving the object’s managed object context. If you continue to modify a value in willSave, willSave will continue to be called until your program crashes.
For example, if you set a last-modified timestamp, you should check whether either you previously set it in the same save operation, or that the existing timestamp is not less than a small delta from the current time. Typically it’s better to calculate the timestamp once for all the objects being saved (for example, in response to an NSManagedObjectContextWillSaveNotification).

Populating an Object from the DB -- Where do you stop?

When getting an object from the DB, should the object's properties also be loaded? There seems to be these approaches.
Create well-formed, fully-loaded objects.
Pro: No need to check if a property has been loaded; it has. Pass it around and don’t worry about parts of the object not being there.
Con: Where do you stop? If an object has an object, and that object has an object, and that object has 40 objects as properties, etc… Do you load the whole DB? Or do you make a decision in the BLL as to what constitutes a well-formed object, and load those properties?
Don’t load any properties that are other objects.
Pro: Quick, no loading unnecessary properties.
Con: Code has to be constantly written to check if properties are populated.
Lazy-loading: only load properties when they are first used.
Pro/Con: Not sure what to say about this approach. It seems intuitively wrong.
Is there another approach? What approach is the best?
And finally, what about properties that can be null? For example, a car may not have a PreviousOwner object. Do you set it to null? An empty PreviousOwner object? Does that property belong in another class then?
There's no easy answer to your question because it depends on what you're trying to achieve.
It looks like you expect a more or less complete object graph to be loaded from the database (i.e. with relationships between multiple object types and the objects themselves stored in the database).
If this is the case, I would look into using the Object Relationship Mapper that's convenient in my language of choice.
As to how much of the object graph is being loaded, the model employed by Apple CoreData's system is objects not yet retrieved are marked as faulty (they call the concept "faulting" - it's described in Limiting the Size of the Object Graph: Faulting. This is a play on the lazy loading concept you described yourself.

Resources