NSManagedObjectContext insertObject - string stored as null - ios

i want to insert a previously created NSManagedObject which has some string attributes into my NSManagedObjectContext via the insertObject method. This seems to work without error but when i reload the saved object again all my string attributes are null.
I have created my entity with:
[[NSManagedObject alloc] initWithEntity:description
insertIntoManagedObjectContext:nil];
Thanks for any constructive feedback.

It is not advisable to insert a "previously created" managed object because it is much more robust to insert it during creation.
If you want to copy a managed object (i.e. "insert it again") effectively creating two instances of it in the persistent store, you will have to create a new one and then copy the all the attributes.
It is certainly more reasonable to insert the object into the context and then delete it if desired. It is just the much more intuitive and documented way to achieve what you want.
I strongly advise against creating a context-less managed object in your usage case!

Related

Orphaned objects in iOS CoreData

Say I have a CoreData entity type called Player and it has a to-one relationship (purpose) with an entity type called PlayerPurpose. For completeness, say we have an inverse relationship in PlayerPurpose called parentPlayer. Consider the following swift code:
// Assume we already have a player object in a NSManagedObjectContext called context:
player.purpose = NSEntityDescription.insertNewObjectForEntityForName("PlayerPurpose",
inManagedObjectContext: context) as PlayerPurpose;
// Later in the code, we set the value to nil (or we could have replaced
// it with another call to insertNewObjectForEntityForName)
player.purpose = nil;
// What happens to the previous playerPurpose object within the Managed Object Context?
My question: what happens to the original playerPurpose object within the Managed Object Context when the only reference it has in the data is set to nil (or replaced with another object)?
This is not really related to relationship deletion rules because I'm not explicitly deleting any object -- I'm removing it from any meaningful relationships, making it an orphan.
From an ARC perspective (if the PlayerPurpose was just a normal, non-managed object), the original PlayerPurpose instance now has no references, so it can be cleared from memory -- but what happens in the Managed Object Context? Does CoreData recognize this as an orphaned object and delete it via the context?
If not, then I assume I have to be careful to delete any managed object created via a context if I'm going to get rid of all references to it. Assuming that's the case, is there a good pattern go use for making sure that orphaned objects get cleared from the NSManagedObjectContext and that they are no longer stored in the persistent store?
Thanks!
Core Data does not automatically delete objects in this scenario, because "orphaned" is a concept that your code has but not one that Core Data recognizes. There's no reason for it to delete a PlayerPurpose object just because one of its relationships is nil.
The most reliable way to ensure that PlayerPurpose instances are deleted would be to
Create custom NSManagedObject subclasses for your entities (if you don't have them already).
Override the setter method for purpose on the Player subclass. If the new value is nil, delete the old one.
You can also handle this by just making sure to call deleteObject: at the appropriate times. Or you could run a clean-up step where you fetch every PlayerPurpose with a nil value for parentPlayer and delete them.

About the benefit of objectWithID:

The doc says:
If the object is not registered in the context, it may be fetched or
returned as a fault. This method always returns an object. The data in
the persistent store represented by objectID is assumed to exist—if it
does not, the returned object throws an exception when you access any
property (that is, when the fault is fired). The benefit of this
behavior is that it allows you to create and use faults, then create
the underlying data later or in a separate context.
I'm thinking about the last sentence:
The benefit of this behavior is that it allows you to create and use faults, then create the underlying data later or in a separate context.
Does it mean I can use objectWithID: with an arbitrary ID to get a fault handle of an non-existing object first then later create the object with ID? But how can I assign an arbitrary ID to the new object?
In general, Yes you can get a handle to a non existing item an later create that item.
But, since you don't know what ID will be assigned to the item these is not very useful in that case.
You could use obtainPermanentIDsForObjects:error: to obtain the object final ID, but, this is a trip to the store, and will have a performance penalty.
You can use objectWithID: to "warm up" the coordinator cache. in this manner you may fetch objects in the background, and use this method in another context then access these items without hitting the store (much better performance).
Since every NSManagedObjectID must initially come from a fulfilled NSManagedObject and there is no way to create one from scratch, the only possible way to "create the underlying data later" is meaningless, as follows:
NSManagedObjectID *objID = object.objectID;
[moc deleteObject:object];
…
object = [moc objectWithID:objID]; // Deleted so non-existing
[moc insertObject:object]; // Kinda of resurrecting the deleted object, but not really since the data are gone only ID is left. So it is creating a new object with the old ID. But what's the point?
// Fill data into object
…
[moc save:NULL];
If you use -objectWithID:, it will return a fault if the object is not already registered in the managed object context (ie. only if the object hasn't already been fetched and hasn't been faulted in). In the case that it does return a fault, you do not need to do anything to "create the object". Simply accessing the attributes of the object will automatically fire the fault and let you access its data. There is no additional work needed on your part to create additional objects.

Best way to have a single Entity using Magicalrecord

I'm looking for the best solution to implement this behavior:
I have an Entity called Customer and this will have only a single entry on Core Data, because the Customer will be only ONE.
What's the best solution to implement this? Is everytime check if the Entity exists before creating?
Many thanks
As mentioned, you can use for single object [NSUserDefaults standardUserDefaults].
But if you prefer use CoreData, write this:
Customer* customer = [Customer MR_findFirst];
if (customer != nil)
{
//do something with it
} else
{
[Customer MR_importFromObject:JSONToImport];
}
BDW:
MR_importFromObject method automatically check if exists entity with specific id (for id key it use attribute of your entity name plus "ID". (in your case "customerID") or key that named "mappedKeyName".
And if entity with this key already exist - Magical Record just update this entity.
So, if you specify this value it in your entity, just write:
[Customer MR_importFromObject:JSONToImport];
If there's only a single instance, the best solution is usually to not put it in Core Data. It gives you very little, and adds complexities like the one you're seeing. Save the necessary information in a property list, or even in user defaults.
Checking the entity exists before creating a new one is a good idea.
You can fetch all entities of your customer entity type and delete them all before adding a new one is another method.
You could also have a simple method that gets the current customer or creates one and then update all it's properties.
It sort of depends on how you get the data and what you want to happen with the related objects.

Deleting or removing ManagedObject in CoreData

In the documentation and in the broad literature the generated factory method to delete/remove a subclassed managed object in CoreData for IOS is
(void)removeXXXObject:(NSManagedObject *)value
where XXX is the corresponding relationship or we can use simply removeObject.
In my code I used this:
Data *lastData = [[self sortedPersonDatas] objectAtIndex:0];
[selectedPerson removePersonDatasObject:lastData];
where PersonDatas is a one-to-many relationship to Data managed object from I took the last data (lastData resulted from a sorted array of all data)
But using the first two remove methods and checking the SQL database behind we can find that the actual data is existing just the inverse relationship is null.
To completely delete the data (all attributes and the object) I had to use:
[selectedPerson.managedObjectContext deleteObject:lastData];
The question: which is the better method and is it correct that CoreData leaves the data intact?
removeXXXObject only removes an object from a to-many relationship, but does not delete the object from the store. To do so, you have to indeed use deleteObject - this is the desired behavior. Calling deleteObject will by default also set the corresponding relationships to nil (see https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html#//apple_ref/doc/uid/TP40001857-SW1).

CoreDataGeneratedAccessors to remove object don't seem to be deleting

I have an NSManagedObject that has a to-many relationship to another NSManagedObject.
During creation of the NSManagedObject I can use the generated accessors 'removeNotesObject' and the deletion works fine. I can create an object to add to the parent object, save the object, delete the object and then save again. When I fetch this parent object the object I created and deleted is still deleted.
However, after I add the object and then save it (but don't delete and save after) and then fetch it, I can't seem to delete the object that was previously created. I am using the generated accessors to try and remove the object, which appears to work but when I fetch it again the object hasn't been deleted.
(Note: Adding objects does work so it is not a problem with the saving)
To delete the object I retrieve the set of object and select the objects I want to delete. Then I remove the objects
NSSet *notes = summary.notes;
NSSet *oldNotes = [notes objectsPassingTest:^(id obj,BOOL *stop){
Note *oldNote = (Note *)obj;
BOOL sameRow = (oldNote.row == newNote.row);
BOOL sameColumn = (oldNote.column == newNote.column);
BOOL success = (sameRow && sameColumn);
return success;}];
[summary removeNotes:oldNotes];
I have tried making the relationship inverse to delete the objects which didn't delete them. I have also tried different delete rules (cascade and nullify) which again didn't work. Finally, I tried to remove each object separately and deleting each object from the context after I had removed it from the parent object which again unfortunately didn't work.
I assume the problem must be something to do with it being a fetched object. If anyone could help I would really appreciate it as I can't think of any other ways to test or solve this problem.
You need to do
NSManagedObjectContext * moc = .......;
[moc deleteObject:note]
edit: The core data generated accessors simply remove the object from the relationship, but do not delete the object permanently. This makes sense because you may have one NSManagedObject associated to multiple other NSManagedObjects via relationships.
edit: Deleting in the above mentioned fashion will invoke the deletion rules. I suggest you double check that they are setup correctly.
The reason the above code did not work is that == will not actually compare the NSNumber. Instead you need to call 'isEqualTo:'. I think before it was checking the address hence working before I saved it. What's more it was returning an object in the NSSet so appeared to be working. During debugging it wasn't clear what the object was but clearly wasn't the one I needed.

Resources