Search code examples
core-datansarraynsset

Why does Core data NSSet invert my array?


I have an array of segments each has an array of fighters associated with it.

The relationship can be described thusly:

One `segment` can have many `fighters`

The objects are managed by core data.

When displayed in a table view each cell has two buttons so a user can pick a fighter from a seperate view controller; and it then when it returns it will update the segment fighter relationship.

Because the relationship of segment.fighters a non-mutable NSSet, I need to modify it so that;

If

  1. User presses left button, this infers that the first object in the segment.fighter is being picked

  2. User presses right button, it infers that the last object in the segment.fighter is being picked

When I come to Update the relationship, sometimes; depending on the sequence of buttons pressed by the user; the positions of the objects in the NSSet are inverted.

ie:

Sometimes a fighter that should be at position 0 is swapped with a fighter at position 1, when this should never happen.

My code is as follows;

NSArray *currentFighters = [[segment valueForKeyPath:@"fighters"] allObjects];

NSLog(@"----- current fighters ---- ");
for (FCFighter *fighter in currentFighters) {
    NSLog(@"%@", [fighter description]);
}

NSMutableArray *currentFightersMutable = [currentFighters mutableCopy];
[currentFightersMutable replaceObjectAtIndex:fighterIdx withObject:pickedFighter];
NSArray *updatedFighters = [currentFightersMutable copy];


NSLog(@"----- updated fighters ---- ");
for (FCFighter *fighter in updatedFighters) {
    NSLog(@"%@", [fighter description]);
}

[segment setFighters:[NSSet setWithArray:updatedFighters]];

NSLog(@"----- [segment fighters] ---- ");
for (FCFighter *fighter in [[segment valueForKeyPath:@"fighters"] allObjects]) {
    NSLog(@"%@", [fighter description]);
}

I am using a NSMutableArray so that I can replace the exact object in the array.

I can prove that it works via logs

Picked fighter - AJ Fonseca 
----- current fighters ---- 
AJ Matthews 
A Sol Kwon 
----- updated fighters ---- 
AJ Fonseca 
A Sol Kwon 
----- [segment fighters] ----   // NOTE it has swapped them, but why?
A Sol Kwon 
AJ Fonseca 
-[FCSegmentTableViewCell configureCellWithSegment:]
#0 -- A Sol Kwon 
#1 -- AJ Fonseca 

However when it gets to segment fighters output, the fighters are swapped; but my question is --

Why does the NSSet invert my array?

Many thanks


Solution

  • An NSSet is an unordered collection of objects. The property allObjects which you use returns an array, but as the documentation for this method states "The order of the objects in the array is undefined.".

    Because of this, whenever you try and get an array out of your set, you could get a different order.

    To make sure the orders don't change, you should either a) use an ordered relationship for the fighters - but not a good idea as NSOrderedSet is a mix between an array and a set. b) apply a sort to the array returned from allObjects so that the order is consistent. This is my preferred method.