Exception levée dans les accesseurs générés par NSOrderedSet

Sur mon application Lion, j’ai ce modèle de données:

entrer la description de l'image ici

Les subitems Item relation dans Item sont classés .

Xcode 4.1 (build 4B110) a créé pour moi le fichier Item.h , Item.m , SubItem.h et SubItem.h .

Voici le contenu (généré automatiquement) de Item.h :

 #import  #import  @class SubItem; @interface Item : NSManagedObject { @private } @property (nonatomic, retain) NSSsortingng * name; @property (nonatomic, retain) NSOrderedSet *subitems; @end @interface Item (CoreDataGeneratedAccessors) - (void)insertObject:(SubItem *)value inSubitemsAtIndex:(NSUInteger)idx; - (void)removeObjectFromSubitemsAtIndex:(NSUInteger)idx; - (void)insertSubitems:(NSArray *)value atIndexes:(NSIndexSet *)indexes; - (void)removeSubitemsAtIndexes:(NSIndexSet *)indexes; - (void)replaceObjectInSubitemsAtIndex:(NSUInteger)idx withObject:(SubItem *)value; - (void)replaceSubitemsAtIndexes:(NSIndexSet *)indexes withSubitems:(NSArray *)values; - (void)addSubitemsObject:(SubItem *)value; - (void)removeSubitemsObject:(SubItem *)value; - (void)addSubitems:(NSOrderedSet *)values; - (void)removeSubitems:(NSOrderedSet *)values; @end 

Et voici le contenu (généré automatiquement) de Item.m :

 #import "Item.h" #import "SubItem.h" @implementation Item @dynamic name; @dynamic subitems; @end 

Comme vous pouvez le voir, la classe Item propose une méthode appelée addSubitemsObject: Malheureusement, lorsque vous essayez de l’utiliser de cette manière:

 Item *item = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:self.managedObjectContext]; item.name = @"FirstItem"; SubItem *subItem = [NSEntityDescription insertNewObjectForEntityForName:@"SubItem" inManagedObjectContext:self.managedObjectContext]; [item addSubitemsObject:subItem]; 

cette erreur apparaît:

 2011-09-12 10:28:45.236 Test[2002:707] *** -[NSSet intersectsSet:]: set argument is not an NSSet 

Pouvez-vous m’aider?

Mettre à jour:

Après seulement 1 787 jours de mon rapport de bogue, aujourd’hui (1er août 2016), Apple m’a écrit ceci: “Veuillez vérifier ce problème avec la dernière version bêta d’iOS 10 et mettre à jour votre rapport de bogue sur bugreport.apple.com.” . Espérons que c’est le bon moment 🙂

J’ai reproduit votre configuration à la fois avec votre modèle de données et un de mes propres noms. J’ai eu la même erreur dans les deux cas.

Ressemble à un bogue dans le code généré automatiquement par Apple.

Je suis d’accord qu’il peut y avoir un bug ici. J’ai modifié l’implémentation du setter d’object add pour l’append correctement à un NSMutableOrderedSet.

 - (void)addSubitemsObject:(SubItem *)value { NSMutableOrderedSet* tempSet = [NSMutableOrderedSet orderedSetWithOrderedSet:self.subitems]; [tempSet addObject:value]; self.subitems = tempSet; } 

Réaffecter l’ensemble à self.subitems garantira que les notifications Will / DidChangeValue seront envoyées.

J’ai décidé d’améliorer la solution en implémentant toutes les méthodes requirejses:

 static NSSsortingng *const kItemsKey = @"<#property#>"; - (void)insertObject:(<#Type#> *)value in<#Property#>AtIndex:(NSUInteger)idx { NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx]; [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey]; NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]]; [tmpOrderedSet insertObject:value atIndex:idx]; [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey]; [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey]; } - (void)removeObjectFrom<#Property#>AtIndex:(NSUInteger)idx { NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx]; [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey]; NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]]; [tmpOrderedSet removeObjectAtIndex:idx]; [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey]; [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey]; } - (void)insert<#Property#>:(NSArray *)values atIndexes:(NSIndexSet *)indexes { [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey]; NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]]; [tmpOrderedSet insertObjects:values atIndexes:indexes]; [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey]; [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey]; } - (void)remove<#Property#>AtIndexes:(NSIndexSet *)indexes { [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey]; NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]]; [tmpOrderedSet removeObjectsAtIndexes:indexes]; [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey]; [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey]; } - (void)replaceObjectIn<#Property#>AtIndex:(NSUInteger)idx withObject:(<#Type#> *)value { NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx]; [self willChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:kItemsKey]; NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]]; [tmpOrderedSet replaceObjectAtIndex:idx withObject:value]; [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey]; [self didChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:kItemsKey]; } - (void)replace<#Property#>AtIndexes:(NSIndexSet *)indexes with<#Property#>:(NSArray *)values { [self willChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:kItemsKey]; NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]]; [tmpOrderedSet replaceObjectsAtIndexes:indexes withObjects:values]; [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey]; [self didChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:kItemsKey]; } - (void)add<#Property#>Object:(<#Type#> *)value { NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]]; NSUInteger idx = [tmpOrderedSet count]; NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx]; [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey]; [tmpOrderedSet addObject:value]; [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey]; [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey]; } - (void)remove<#Property#>Object:(<#Type#> *)value { NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]]; NSUInteger idx = [tmpOrderedSet indexOfObject:value]; if (idx != NSNotFound) { NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx]; [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey]; [tmpOrderedSet removeObject:value]; [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey]; [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey]; } } - (void)add<#Property#>:(NSOrderedSet *)values { NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]]; NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet]; NSUInteger valuesCount = [values count]; NSUInteger objectsCount = [tmpOrderedSet count]; for (NSUInteger i = 0; i < valuesCount; ++i) { [indexes addIndex:(objectsCount + i)]; } if (valuesCount > 0) { [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey]; [tmpOrderedSet addObjectsFromArray:[values array]]; [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey]; [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey]; } } - (void)remove<#Property#>:(NSOrderedSet *)values { NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]]; NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet]; for (id value in values) { NSUInteger idx = [tmpOrderedSet indexOfObject:value]; if (idx != NSNotFound) { [indexes addIndex:idx]; } } if ([indexes count] > 0) { [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey]; [tmpOrderedSet removeObjectsAtIndexes:indexes]; [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey]; [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey]; } } 

Oui, il s’agit bien d’un bogue de firebase database. Il y a quelque temps, j’ai écrit un correctif basé sur ObjC-Runtime, mais à l’époque, je pensais qu’il serait bientôt corrigé. Quoi qu’il en soit, pas de chance, alors je l’ai posté sur GitHub en tant que KCOrderedAccessorFix . Contournez le problème sur toutes vos entités:

 [managedObjectModel kc_generateOrderedSetAccessors]; 

Une entité en particulier:

 [managedObjectModel kc_generateOrderedSetAccessorsForEntity:entity]; 

Ou juste pour une relation:

 [managedObjectModel kc_generateOrderedSetAccessorsForRelationship:relationship]; 

Au lieu de faire une copie, je suggère d’utiliser l’accesseur dans NSObject pour avoir access à NSMutableOrderedSet des relations.

 - (void)addSubitemsObject:(SubItem *)value { NSMutableOrderedSet* tempSet = [self mutableOrderedSetValueForKey:@"subitems"]; [tempSet addObject:value]; } 

Par exemple, les notes de publication Core Data pour iOS v5.0 s’y réfèrent.

Dans un test rapide, cela a fonctionné dans mon application.

J’ai suivi le bug. Cela se produit dans willChangeValueForKey:withSetMutation:usingObjects:

Cet appel déclenche une chaîne de notifications qui peut être difficile à suivre et, bien sûr, les modifications apscopes à un répondeur peuvent avoir des implications pour un autre, ce qui est sans doute la raison pour laquelle Apple n’a rien fait.

Cependant, il est correct de définir dans Set et ses seules opérations sur un OrderedSet. Cela signifie qu’il n’y a que quatre méthodes à modifier. Par conséquent, tout ce que j’ai fait, c’est de convertir les opérations Set en opérations Array équivalentes. Celles-ci fonctionnent parfaitement et les frais généraux sont minimes (mais nécessaires).

À un niveau critique, cette solution souffre d’une faille critique. Si vous ajoutez des objects et que l’un des objects existe déjà, il n’est pas ajouté ou déplacé au dos de la liste ordonnée (je ne sais pas lequel). Dans les deux cas, l’index ordonné attendu de l’object au moment où nous arrivons à didChange est différent de ce qui était prévu. Cela peut casser les applications de certaines personnes, mais cela n’affecte pas le mien, puisque je n’ajoute que de nouveaux objects ou que je confirme leur emplacement final avant de les append.

 - (void)addChildrenObject:(BAFinancialItem *)value { if ([self.children containsObject:value]) { return; } NSIndexSet * indexSet = [NSIndexSet indexSetWithIndex:self.children.count]; [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexSet forKey:ChildrenKey]; [[self primitiveValueForKey:ChildrenKey] addObject:value]; [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexSet forKey:ChildrenKey]; } - (void)removeChildrenObject:(BAFinancialItem *)value { if (![self.children containsObject:value]) { return; } NSIndexSet * indexSet = [NSIndexSet indexSetWithIndex:[self.children indexOfObject:value]]; [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexSet forKey:ChildrenKey]; [[self primitiveValueForKey:ChildrenKey] removeObject:value]; [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexSet forKey:ChildrenKey]; } - (void)addChildren:(NSOrderedSet *)values { if ([values isSubsetOfOrderedSet:self.children]) { return; } NSIndexSet * indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(self.children.count, values.count)]; [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexSet forKey:ChildrenKey]; [[self primitiveValueForKey:ChildrenKey] unionOrderedSet:values]; [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexSet forKey:ChildrenKey]; } - (void)removeChildren:(NSOrderedSet *)values { if (![self.children intersectsOrderedSet:values]) { return; } NSIndexSet * indexSet = [self.children indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { return [values containsObject:obj]; }]; [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexSet forKey:ChildrenKey]; [[self primitiveValueForKey:ChildrenKey] minusOrderedSet:values]; [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexSet forKey:ChildrenKey]; } 

Bien sûr, la solution est plus simple. c’est comme suit:

 - (void)addChildrenObject:(BAFinancialItem *)value { if ([self.children containsObject:value]) { return; } [self insertObject:value inChildrenAtIndex:self.children.count]; } - (void)removeChildrenObject:(BAFinancialItem *)value { if (![self.children containsObject:value]) { return; } [self removeObjectFromChildrenAtIndex:[self.children indexOfObject:value]]; } - (void)addChildren:(NSOrderedSet *)values { if ([values isSubsetOfOrderedSet:self.children]) { return; } [self insertChildren:values atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(self.children.count, values.count)]]; } - (void)removeChildren:(NSOrderedSet *)values { if (![self.children intersectsOrderedSet:values]) { return; } [self removeChildrenAtIndexes:[self.children indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { return [values containsObject:obj]; }]]; } 

Le document d’Apple To Many Relations indique: vous devez accéder à l’ensemble proxy modifiable ou à l’ensemble ordonné en utilisant

 NSMutableOrderedSet * set = [managedObject mutableOrderedSetValueForKey:@"toManyRelation"]; 

La modification de cet ensemble appenda ou supprimera des relations à votre object géré. Accéder à l’ensemble ordonné modifiable à l’aide de l’accesseur, que ce soit avec [] ou. la notation est fausse et échouera.

Reçu la même erreur, la solution @LeeIII a fonctionné pour moi (merci!). Je suggère de le modifier légèrement:

  • utiliser la catégorie objective-c pour stocker la nouvelle méthode (afin de ne pas perdre notre méthode si Item est généré à nouveau)
  • vérifier si nous avons déjà mis en mutable

Contenu de l’ Item+category.m :

 #import "Item+category.h" @implementation Item (category) - (void)addSubitemsObject:(SubItem *)value { if ([self.subitems isKindOfClass:[NSMutableOrderedSet class]]) { [(NSMutableOrderedSet *)self.subitems addObject:value]; } else { NSMutableOrderedSet* tempSet = [NSMutableOrderedSet orderedSetWithOrderedSet:self.subitems]; [tempSet addObject:value]; self.subitems = tempSet; } } @end 

Si vous utilisez un générateur, alors au lieu de

 [parentObject addsObject:childObject]; 

utilisez simplement:

 [[parent object sSet] addObject:childObject]; 

Personnellement, je viens de remplacer les appels aux méthodes générées par CoreData par des appels directs à la méthode, comme indiqué dans une autre solution de @Stephan:

 NSMutableOrderedSet* tempSet = [self mutableOrderedSetValueForKey:@"subitems"]; [tempSet addObject:value]; [tempSet addObject:value]; 

Cela supprime le besoin de catégories susceptibles d’entrer en conflit avec une solution d’Apple au code généré lorsque le bogue est résolu.

Cela a l’avantage d’être le moyen officiel de le faire!

Il semble que si vous liez le parent avec l’enfant en définissant le parent à l’enfant et non l’inverse, cela fonctionne sans se planter.

Donc, si vous faites:

 [child setParent:parent] 

au lieu de

 [parent setChildObects:child] 

Cela devrait fonctionner, au moins ça marche sur iOS 7 et n’a eu aucun problème avec la relation.

J’ai eu le même problème, mais seulement quand j’ai essayé quelque chose de différent de ce que je faisais. Je ne peux pas voir le code pour subItem, mais je suppose qu’il a un lien inverse à l’élément. Appelons ce lien reveres, “parentItem”, alors la solution la plus simple est la suivante:

 Item *item = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:self.managedObjectContext]; item.name = @"FirstItem"; SubItem *subItem = [NSEntityDescription insertNewObjectForEntityForName:@"SubItem" inManagedObjectContext:self.managedObjectContext]; //[item addSubitemsObject:subItem]; subItem.parentItem = item; 

L’effet est qu’il utilise le propre code d’Apple et qu’il est simple et propre. En outre, le jeu est automatiquement ajouté et tous les observateurs sont mis à jour. Aucun problème.

Je suis juste tombé sous le coup de ce problème et je l’ai résolu en utilisant une implémentation beaucoup plus simple que les autres décrites ici. J’utilise simplement les méthodes disponibles sur NSManagedObject pour gérer les relations lorsque vous n’utilisez pas de sous-classes.

Un exemple d’implémentation pour insérer une entité dans une relation NSOrderedSet ressemblerait à ceci:

 - (void)addAddress:(Address *)address { if ([self.addresses containsObject:address]) { return; } // Use NSManagedObject's methods for inserting an object [[self mutableOrderedSetValueForKey:@"addresses"] addObject:address]; } 

Cela fonctionne parfaitement et c’est ce que j’utilisais avant de passer aux sous-classes NSManagedObject .

Ce problème m’est apparu lors de la migration d’un projet d’Objective-C vers Swift 2 avec XCode 7 . Ce projet fonctionnait, et pour une bonne raison: j’utilisais MOGenerator qui avait des méthodes de remplacement pour résoudre ce problème. Mais toutes les méthodes ne nécessitent pas de remplacement.

Donc, voici la solution complète avec un exemple de classe, en s’appuyant autant que possible sur les accesseurs par défaut.

Disons que nous avons une liste avec les articles commandés

D’abord un gain rapide si vous avez une relation un-à-plusieurs, le plus simple est de faire:

 item.list = list 

au lieu de

 list.addItemsObject(item) 

Maintenant, si ce n’est pas une option , voici ce que vous pouvez faire:

 // Extension created from your DataModel by selecting it and // clicking on "Editor > Create NSManagedObject subclass…" extension List { @NSManaged var items: NSOrderedSet? } class List // Those two methods work out of the box for free, relying on // Core Data's KVC accessors, you just have to declare them // See release note 17583057 https://developer.apple.com/library/prerelease/tvos/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc7_release_notes.html @NSManaged func removeItemsObject(item: Item) @NSManaged func removeItems(items: NSOrderedSet) // The following two methods usually work too, but not for NSOrderedSet // @NSManaged func addItemsObject(item: Item) // @NSManaged func addItems(items: NSOrderedSet) // So we'll replace them with theses // A mutable computed property var itemsSet: NSMutableOrderedSet { willAccessValueForKey("items") let result = mutableOrderedSetValueForKey("items") didAccessValueForKey("items") return result } func addItemsObject(value: Item) { itemsSet.addObject(value) } func addItems(value: NSOrderedSet) { itemsSet.unionOrderedSet(value) } end 

Bien sûr, si vous utilisez Objective-C, vous pouvez faire exactement la même chose puisque c’est là que j’ai eu l’idée en premier lieu 🙂

Je suis d’accord qu’il y a peut-être un bug ici. J’ai modifié l’implémentation de l’object add> setter pour l’append correctement à un NSMutableOrderedSet.

 - (void)addSubitemsObject:(SubItem *)value { NSMutableOrderedSet* tempSet = [NSMutableOrderedSet orderedSetWithOrderedSet:self.subitems]; [tempSet addObject:value]; self.subitems = tempSet; } 

Réaffecter l’ensemble à self.subitems garantira que les notifications Will / DidChangeValue> sont envoyées.

Leelll, êtes-vous sûr qu’après une telle configuration personnalisée de NSMutableOrderedSet, les valeurs stockées dans cet ensemble seront correctement enregistrées dans la firebase database par CoreData? Je n’ai pas vérifié cela, mais on dirait que CoreData ne sait rien de NSOrderedSet et attend NSSet comme conteneur de relation à plusieurs.

Je pense que tout le monde manque le vrai problème. Ce n’est pas dans les méthodes d’ NSOrderedSet mais plutôt dans le fait que NSOrderedSet n’est pas une sous-classe de NSSet . Donc, quand -interSectsSet: est appelé avec un ensemble ordonné comme argument, il échoue.

 NSOrderedSet* setA = [NSOrderedSet orderedSetWithObjects:@"A",@"B",@"C",nil]; NSSet* setB = [NSSet setWithObjects:@"C",@"D", nil]; [setB intersectsSet:setA]; 

échoue avec *** -[NSSet intersectsSet:]: set argument is not an NSSet

Looks like the fix is to change the implementation of the set operators so they handle the types transparently. No reason why a -intersectsSet: should work with either an ordered or unordered set.

The exception happens in the change notification. Presumably in the code that handles the inverse relationship. Since it only happens if I set an inverse relationship.

The following did the sortingck for me

 @implementation MF_NSOrderedSetFixes + (void) fixSetMethods { NSArray* classes = [NSArray arrayWithObjects:@"NSSet", @"NSMutableSet", @"NSOrderedSet", @"NSMutableOrderedSet",nil]; [classes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSSsortingng* name = obj; Class aClass = objc_lookUpClass([name UTF8Ssortingng]); [MF_NSOrderedSetFixes fixMethodWithSetArgument:@selector(intersectsSet:) forClass:aClass]; [MF_NSOrderedSetFixes fixMethodWithSetArgument:@selector(isSubsetOfSet:) forClass:aClass]; }]; } typedef BOOL (*BoolNSetIMP)(id _s,SEL sel, NSSet*); /* Works for all methods of type - (BOOL) method:(NSSet*) aSet */ + (void) fixMethodWithSetArgument:(SEL) aSel forClass:(Class) aClass { /* Check that class actually implements method first */ /* can't use get_classInstanceMethod() since it checks superclass */ unsigned int count,i; Method method = NULL; Method* methods = class_copyMethodList(aClass, &count); if(methods) { for(i=0;i 

I just got the problem in Swift (Xcode 6.1.1).

The answer was DO NOT CODE ANY METHOD OR ADDITIONAL THINGS in your NSManagedObject subclasses. I think it is a compilator mistake. Very strange bug ..

Hope it helps ..

I solved this problem by set the inverse to No Inverse, I don’t know why, Maybe there is Apple Bug. entrer la description de l'image ici

I have the same situation with an item called “signals” instead of “subitems”. The solution with tempset works in my testing. Further, I had a problem with the removeSignals: method. This override seems to work:

 - (void)removeSignals:(NSOrderedSet *)values { NSMutableOrderedSet* tempset = [NSMutableOrderedSet orderedSetWithOrderedSet:self.signals]; for (Signal* aSignal in values) { [tempset removeObject:aSignal]; } self.signals = tempset; } 

If there is a better way to do this, please let me know. My values input is never more than 10 -20 items so performance isn’t much of a concern – nonetheless please point out anything relevant.

Merci,

Damien

I found this question by googling for the error message, and just wanted to point out that I ran into this error in a slightly different way (not using ordered sets). This isn’t quite an answer to the given question, but I’m posting it here just in case it is helpful to anyone else who stumbles across this question while searching.

I was adding a new model version, and added some relationships to existing models, and defined the add*Object methods in the header file myself. When I sortinged to call them, I got the error above.

After reviewing my models, I realized I had stupidly forgotten to check the “To-Many Relationship” checkbox.

So if you’re running into this and you’re not using ordered sets, double check your model.

I found a fix for this bug that works for me. I just replace this:

 [item addSubitemsObject:subItem]; 

with this:

 item.subitemsObject = subItem; 

I found using the method by LeeIII worked, but on profiling found it was drastically slow. It took 15 seconds to parse 1000 items. Commenting out the code to add the relationship turned 15 seconds into 2 seconds.

My workaround (which is faster but much more ugly) involves creating a temporary mutable array then copying into the ordered set when all the parsing is done. (this is only a performance win if you are going to add many relationships).

 @property (nonatomic, retain) NSMutableArray* tempItems; .... @synthesize tempItems = _tempItems; .... - (void) addItemsObject:(KDItem *)value { if (!_tempItems) { self.tempItems = [NSMutableArray arrayWithCapacity:500]; } [_tempItems addObject:value]; } // Call this when you have added all the relationships - (void) commitRelationships { if (_tempItems) { self.items = [NSOrderedSet orderedSetWithArray:self.tempItems]; self.tempItems = nil; } } 

I hope this help someone else!

Robert,

I agree your answer will work for this, but keep in mind that there is an automatically created method for adding a whole set of values to a relationship already. Apple’s Documentation ( as seen here under the “To-many Relationships” section or here under the “Custom To-Many Relationship Accessor Methods” section) implements them this way:

 - (void)addEmployees:(NSSet *)value { [self willChangeValueForKey:@"employees" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value]; [[self primitiveEmployees] unionSet:value]; [self didChangeValueForKey:@"employees" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value]; } - (void)removeEmployees:(NSSet *)value { [self willChangeValueForKey:@"employees" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value]; [[self primitiveEmployees] minusSet:value]; [self didChangeValueForKey:@"employees" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value]; } 

You could easily comstack your set of relationships outside of core data and then add them all at once using this method. It might be less ugly than the method you suggested 😉

I’m quite sure it is finally fixed in iOS 10 beta 6 !

Better version of the correct answer in SWIFT

 var tempSet = NSMutableOrderedSet() if parent!.subItems != nil { tempSet = NSMutableOrderedSet(orderedSet: parent!.subItems!) } tempSet.add(newItem) parent!.subItems = tempSet