How to replace all ordered to-many relationships in NSManagedObject ios - ios

First, please note, I'm aware of the NSOrderedSet bug.
I think the issue I have is that I don't fully understand removeXXX:(NSOrderedSet*)values.
I want to replace and old ordered set with a new ordered set of objects.
What I would have thought is:
[object removeXXX];
[object addXXX:newSet];
So I don't understand the values passed to removeXXX:
Is it possible to merely set the property?:
object.relation = newSet;

Related

CoreData "forgets" order of NSOrderedSet relationship

I have a NSOrderedSet relaitonship on an entity. The order of the objects is correct until I save, quit and relaunch the app. Then, when the entity is fetched, For some instances of the entity, the order of this relaitonship is different from what it was prior to the relaunch. It's as if the NSOrderedSet completely forgot the order.
Inspecting the model file shows that this property is indeed ordered:
<relationship name="videoSegments" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="VideoSegment" inverseName="parentProject" inverseEntity="VideoSegment" syncable="YES"/>
I know about the autogenerated accessor code issue: Exception thrown in NSOrderedSet generated accessors however this is a different problem although it may be related somehow.
It doesn't forget anything, you should sort it. There is a difference between ordered and sorted.
Check NSMutableOrderedSet
If you need to return the data in a specific order, you need to add an attribute which defines the sort order, such as an index from 0..n, and sort the results on that.
CoreData doesn't pay any attention to the order in which you added the data

Get the Type of a Core Data relationship

Is there an easy way to find the object type which forms a specific relationship in Core Data?
For example, I have a one-to-many relationship:
Battery-----1-to-Many-----Comment
If I didn't know that the relationship was for a specific Comment object, is there a programatic way I could find out which object type it is, based solely on the set that I'm dealing with.
Something along the lines of
battery.comments.classType = [Comment class]
I'm aware that both Battery and Comment are of type NSManagedObject - I'd like to know more specifically what they are.
I'm also aware that if the NSSet contains any data, I can use any one of it's objects to query the type. However I need to cater for when there is no data in the NSSet.
Thank you.
You can get all info you need from this few lines:
NSRelationshipDescription* rel = [[[battery entity] relationshipsByName] valueForKey:#"comments"];
NSString* className = [[rel destinationEntity] managedObjectClassName];
NSString* entityName = [[rel destinationEntity] name];
In your AppDelegate you have an NSManagedObjectModel typed property. It has an entities array containing NSEntityDescriptions. From here you should be able to figure it out. Hope this helps!

Core data replacing to-many set

Quick question, if I want to replace a to-many relationship completely. Do I need to delete all the previous objects, or is that done automatically
newVariable.hasRel = [NSSet setWithSet:newSet];
Where the variable has had some objects in that set, will just replacing it with the new set get rid of the old entities ???
Quick answer: Assigning a new set of related objects does not delete the previously related objects. You have to do that manually.

Does using a class and dot notation access in Core Data get a mutable set?

I have an entity called LogBook which has an attribute (called columns) for a set of LogBookColumn entities (one-to-many relationship).
The standard way I see to retrieve the mutable set of columns seems to be:
NSEntityDescription *myLogbook;
myLogbook = [NSEntityDescription insertNewObjectForEntityForName:#"LogBook"
inManagedObjectContext:self.managedObjectContext];
NSMutableSet *columns = [myLogbook mutableSetValueForKey:#"columns"];
Instead of method on the third line, I want to use dot notation. To do so, I have created class definitions, also called LogBook and LogBookColumn, and use #property to create the setters and getters.
LogBook *myLogBook;
myLogbook = [NSEntityDescription insertNewObjectForEntityForName:#"LogBook"
inManagedObjectContext:self.managedObjectContext];
NSMutableSet *columns = (NSMutableSet *)myLogbook.columns;
So, is columns truly a mutable set by default? I have done two things to verify:
Attempted to write to the list, eg: [columns addObject:aColumn];
Asked with: BOOL isKindOfMutableSet = [myLogbook.columns isKindOfClass:[NSMutableSet class]];
Both work with expected results, which may make this question overkill, but I am very concerned about memory errors that will be difficult to track down. I also wonder if asking the question isKindOfClass will work as I have defined this as a mutable set - so won't it work even if the underlying memory organization doesn't support mutable sets?
All of the above sums up to: is this the right way to access and change the columns property/attribute?
According to this documentation, to-many relationships should be declared as NSSet, which makes sense. Even if the attribute returns an NSMutableSet, it is not guaranteed that updating the NSMutableSet will properly update relationships (which mutableSetValueForKey: does).
If you really want a mutable accessor, then just create a readonly property that wraps mutableSetValueForKey:
Update:
Otherwise, we are supposed to use - (void)addLogBookColumnsObject:(LogBookColumn *)value;, - (void)removeLogBookColumnsObject:(LogBookColumn *)value;, - (void)addLogBookColumns:(NSSet *)values;, - (void)removeLogBookColumns:(NSSet *)values; that were generated by Core Data for us.

Core Data: object in a predicate

In my core data object model I have 3 entities with appropriate relationships so that MyObject can have many MyObjectProperties, and each property can have one MyObjectPropertyImage.
Given a myObject I want to fetch all the images.
I try to do it using the following predicate, however I get an empty array:
[NSEntityDescription entityForName:#"MyObjectPropertyImage" inManagedObjectContext:managedObjectContext];
[NSPredicate predicateWithFormat:#"ANY myObjectProperty.myObject == %#", myObject];
Any ideas?
When working with Core Data it's best to think of your entities as just that: entities in an object graph, instead of tables in a database. Therefore, you don't need to fetch entities related to others using a predicate. Instead, navigate the object graph using the relationships defined in the model. To get all the images related to myObject:
// assuming the relationships are called 'myObjectProperties' and 'myObjectPropertyImage', respectively
NSSet *allImages = [myObject.myObjectProperties valueForKey:#"myObjectPropertyImage"];
Note that this may trigger additional trips to the database if your object graph is not loaded in memory for your myObject entity. To avoid that, make sure you set the pre-fetching relationship keypaths in your fetch request for myObject.
I hope this helps...
Since you have a MyObject instance in hand and it has the relationship path of myObjectProperties-->ObjectProperty-->>PropertyImages you just need to traverse the relationships. It's easy to do this with valueForKeyPath:
Thusly:
NSArray *images=[myObjectInstances valueForKeyPath:#"myObjectProperties.propertyImage"];
(Note: I might have your attribute names wrong but you can get the idea.)
As general rule, you never fetch when have an object from the graph available. You fetch to "pick out thread" of objects matching the predicate and then to find all related objects you follow the thread/relationships to the related objects.

Resources