Exceção lançada em acessadores gerados NSOrderedSet

No meu aplicativo Lion, eu tenho este modelo de dados:

insira a descrição da imagem aqui

Os subitems relacionamento dentro de Item são ordenados .

O Xcode 4.1 (build 4B110) criou para mim o arquivo Item.h , Item.m , SubItem.h e SubItem.h .

Aqui está o conteúdo ( Item.h automaticamente) do Item.h :

 #import  #import  @class SubItem; @interface Item : NSManagedObject { @private } @property (nonatomic, retain) NSString * 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 

E aqui está o conteúdo ( Item.m ) do Item.m :

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

Como você pode ver, a class Item oferece um método chamado addSubitemsObject: Infelizmente, ao tentar usá-lo desta maneira:

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

este erro aparece:

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

Pode me ajudar?

Atualizar:

Após apenas 1.787 dias do meu relatório de bug, hoje (1 de agosto de 2016) a Apple me escreveu o seguinte: “Verifique este problema com a versão beta mais recente do iOS 10 e atualize seu relatório de erros em bugreport.apple.com com seus resultados.” . Vamos esperar que este seja o momento certo 🙂

Eu reproduzi a sua configuração tanto com o seu modelo de dados e um dos meus com nomes diferentes. Eu tenho o mesmo erro em ambos os casos.

Parece um bug no código autogerado da Apple.

Eu concordo que pode haver um bug aqui. Eu modifiquei a implementação do setter de object add para append corretamente a um NSMutableOrderedSet.

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

A reatribuição do conjunto a self.subitems garantirá que as notifications Will / DidChangeValue sejam enviadas.

Decidi melhorar a solução implementando todos os methods necessários:

 static NSString *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]; } } 

Sim, esse é definitivamente um bug do Core Data. Eu escrevi uma correção baseada em Runtime do ObjC há algum tempo, mas na época percebi que seria corrigida em breve. De qualquer forma, sem essa sorte, então eu postei no GitHub como KCOrderedAccessorFix . Resolva o problema em todas as suas entidades:

 [managedObjectModel kc_generateOrderedSetAccessors]; 

Uma entidade em particular:

 [managedObjectModel kc_generateOrderedSetAccessorsForEntity:entity]; 

Ou apenas para um relacionamento:

 [managedObjectModel kc_generateOrderedSetAccessorsForRelationship:relationship]; 

Em vez de fazer uma cópia, sugiro usar o acessador no NSObject para obter access ao NSMutableOrderedSet dos relacionamentos.

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

por exemplo, as Notas de Lançamento de Dados Principais para iOS v5.0 referem-se a isso.

Em um teste curto, funcionou no meu aplicativo.

Eu segui o bug. Ocorre em willChangeValueForKey:withSetMutation:usingObjects:

Esta chamada desencadeia uma cadeia de notifications que pode ser difícil de acompanhar, e é claro que as mudanças em um respondente podem ter implicações para outro, que eu suspeito é por que a Apple não fez nada.

No entanto, está tudo bem em Set e é apenas o conjunto de operações em um OrderedSet que não funcionam corretamente. Isso significa que existem apenas quatro methods que precisam ser alterados. Portanto, tudo que fiz foi converter as operações Set em suas operações de Matriz equivalentes. Estes funcionam perfeitamente e mínimo (mas necessário) despesas gerais.

Em um nível crítico, esta solução sofre de uma falha crítica; se você estiver adicionando objects e um dos objects já existir, ele não será adicionado ou movido para o final da lista ordenada (não sei qual). Em ambos os casos, o índice esperado esperado do object no momento em que chegamos ao didChange é diferente do que foi antecipado. Isso pode interromper os aplicativos de algumas pessoas, mas isso não afeta o meu, já que estou adicionando apenas novos objects ou confirmo seus locais finais antes de adicioná-los.

 - (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]; } 

Claro, existe uma solução mais fácil. é como segue;

 - (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]; }]]; } 

A documentação da Apple para muitas relações diz: você deve acessar o conjunto mutável de proxy ou conjunto ordenado usando

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

Modificar esse conjunto adicionará ou removerá relações ao seu object gerenciado. Acessando o conjunto ordenado mutável usando o acessador seja com [] ou. a notação está errada e falhará.

Recebeu o mesmo erro, a solução @LeeIII funcionou para mim (obrigado!). Sugiro modificá-lo ligeiramente:

  • use object-c category para armazenar o novo método (assim não perderemos nosso método se o Item for gerado novamente)
  • verifique se já temos um conjunto mutável

Conteúdo do 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 

Se você estiver usando mogenerator, então ao invés de

 [parentObject addsObject:childObject]; 

simplesmente use:

 [[parent object sSet] addObject:childObject]; 

Pessoalmente, acabei de replace as chamadas para os methods gerados CoreData por chamadas diretas ao método, conforme descrito em outra solução por @Stephan:

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

Isso elimina a necessidade de categorias que possam entrar em conflito com uma solução da Apple para o código gerado quando o bug for corrigido.

Isto tem a vantagem adicional de ser a maneira oficial de fazer isso!

Parece que se você vincular o pai ao filho, definindo o pai para o filho e não o contrário, ele funcionará sem travar.

Então, se você fizer:

 [child setParent:parent] 

ao invés de

 [parent setChildObects:child] 

Deve funcionar, pelo menos funciona no iOS 7 e não teve problemas com o relacionamento.

Eu tive o mesmo problema, mas apenas quando tentei algo diferente do que eu vinha fazendo. Não consigo ver o código para subItem, mas vou assumir que ele tem um link reverso para o item. Vamos chamar isto de reverenciar link, “parentItem”, então a solução mais fácil é esta:

 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; 

O efeito é que faz uso do próprio código da Apple e é simples e limpo. Além disso, o conjunto é adicionado automaticamente e todos os observadores são atualizados. Sem problemas.

Acabei de me deparar com este problema e resolvi-o usando uma implementação muito mais simples do que as outras descritas aqui. Eu simplesmente faço uso dos methods disponíveis em NSManagedObject para lidar com relacionamentos quando não estiver usando subclasss.

Um exemplo de implementação para inserir uma entidade em um relacionamento NSOrderedSet seria assim:

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

Isso funciona perfeitamente e é o que eu estava usando antes de me mudar para as subclasss NSManagedObject .

Esse problema ocorreu durante a migration de um projeto do Objective-C para o Swift 2 com o XCode 7 . Esse projeto costumava funcionar e por um bom motivo: eu estava usando o MOGenerator, que tinha methods de substituição para corrigir esse bug. Mas nem todos os methods exigem uma substituição.

Então aqui está a solução completa com uma class de exemplo, contando com acessadores padrão tanto quanto possível.

Digamos que temos uma lista com itens ordenados

Primeiro, uma vitória rápida se você tiver um relacionamento de um para muitos, o mais fácil é simplesmente fazer:

 item.list = list 

ao invés de

 list.addItemsObject(item) 

Agora, se isso não for uma opção , veja o que você pode fazer:

 // 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 

Claro, se você estiver usando o Objective-C, você pode fazer exatamente a mesma coisa, já que foi aí que eu tive a idéia.

Eu concordo que talvez haja um bug aqui. Eu modifiquei a implementação do add object setter para append corretamente a um NSMutableOrderedSet.

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

A reatribuição do conjunto a self.subitems garantirá que as notifications Will / DidChangeValue> sejam enviadas.

Leelll, você tem certeza de que, após essa configuração personalizada de NSMutableOrderedSet, os valores armazenados nesse conjunto serão salvos no database corretamente pelo CoreData? Eu não verifiquei isso, mas parece que o CoreData não sabe nada sobre o NSOrderedSet e espera o NSSet como muitos contêiner de relacionamento.

Eu acho que todo mundo está perdendo o problema real. Não está nos methods acessadores, mas sim no fato de que NSOrderedSet não é uma subclass de NSSet . Então, quando -interSectsSet: é chamado com um conjunto ordenado como argumento, ele falha.

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

falha com *** -[NSSet intersectsSet:]: set argument is not an NSSet

Parece que a solução é mudar a implementação dos operadores do conjunto para que eles lidem com os tipos de forma transparente. Não há razão para que um -intersectsSet: funcione com um conjunto ordenado ou não ordenado.

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 trick for me

 @implementation MF_NSOrderedSetFixes + (void) fixSetMethods { NSArray* classs = [NSArray arrayWithObjects:@"NSSet", @"NSMutableSet", @"NSOrderedSet", @"NSMutableOrderedSet",nil]; [classs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSString* name = obj; Class aClass = objc_lookUpClass([name UTF8String]); [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 subclasss. 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. insira a descrição da imagem aqui

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.

Obrigado,

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 tried 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]; 

com isso:

 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 compile 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