在NSOrderedSet生成的访问器中抛出exception

在我的狮子应用程序,我有这个数据模型:

在这里输入图像描述

Item内部的关系subitems 是有序的

Xcode 4.1(build 4B110)为我创build了文件Item.hItem.mSubItem.hSubItem.h

这里是Item.h的内容(自动生成):

 #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> @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 

这里是Item.m的内容(自动生成)

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

如您所见,类Item提供了一个名为addSubitemsObject:的方法。 不幸的是,当试图以这种方式使用它时:

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

出现此错误:

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

你可以帮我吗?

更新:

从我的错误报告仅仅1,787天后,今天(2016年8月1日),苹果公司给我写道: “请用最新的iOS 10testing版本来validation这个问题,并用bugreport.apple.com更新您的错误报告。 。 让我们希望这是正确的时间:)

我用您的数据模型和我自己的不同名称复制了您的设置。 在两种情况下,我都遇到了同样的错误。

看起来像苹果自动生成的代码中的错误。

我同意这里可能有一个错误。 我已经修改了添加对象设置器的实现,以正确地附加到NSMutableOrderedSet。

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

将该集重新分配给self.subitems将确保发送Will / DidChangeValue通知。

我决定通过实施所有必要的方法来改进解决scheme:

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

是的,这绝对是一个核心数据错误。 我写了一个基于ObjC-Runtime的修复,但是当时我觉得它很快就会被修复。 无论如何,没有这样的运气,所以我把它作为KCOrderedAccessorFix贴在GitHub上。 解决所有实体上的问题:

 [managedObjectModel kc_generateOrderedSetAccessors]; 

一个实体特别是:

 [managedObjectModel kc_generateOrderedSetAccessorsForEntity:entity]; 

或者只是一个关系:

 [managedObjectModel kc_generateOrderedSetAccessorsForRelationship:relationship]; 

而不是做一个副本,我build议在NSObject中使用访问器来访问关系的NSMutableOrderedSet。

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

例如, 针对iOS v5.0的核心数据发行说明参考这个。

在一个简短的testing,它在我的应用程序工作。

我跟踪了这​​个错误。 它发生在willChangeValueForKey:withSetMutation:usingObjects:

这个呼叫引发了一系列可能难以追踪的通知,当然一个响应者的变化可能对另一个响应者有影响,我怀疑苹果为什么什么也不做。

但是,在Set中它是可以的,并且它在OrderedSet上只有Set操作发生故障。 这意味着只有四种方法需要改变。 因此,我所做的就是将Set操作转换为等效的Array操作。 这些工作完美和最小(但必要)的开销。

在临界水平上,这个解决scheme确实遭受了一个严重的缺陷。 如果你添加的对象和其中一个对象已经存在,那么要么不被添加或移动到有序列表的后面(我不知道是哪个)。 在任何一种情况下,到达didChange时对象的预期有序索引都与预期的不同。 这可能会打破一些人的应用程序,但它不会影响我的,因为我只是添加新的对象,或者我添加之前确认他们的最终位置。

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

当然,有一个更简单的解决scheme。 具体如下:

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

苹果公司的文档多关系说:你应该访问代理可变集或有序集使用

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

修改此设置将添加或删除您的pipe理对象的关系。 使用访问器访问可变的有序集合,无论是使用[]还是使用访问器。 符号是错误的,将失败。

收到同样的错误,@ LeeIII解决scheme为我工作(谢谢!)。 我build议稍微修改一下:

  • 使用objective-c类别来存储新的方法(所以如果再次生成Item,我们不会丢失我们的方法)
  • 检查我们是否已经有可变集合

Item+category.m内容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 

如果你正在使用mogenerator,那么,而不是

 [parentObject add<Child>sObject:childObject]; 

只需使用:

 [[parent object <child>sSet] addObject:childObject]; 

就我个人而言,我刚刚用@Stephan的另一个解决scheme中的方法直接调用方法,将调用replace为CoreData生成的方法:

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

这样就消除了需要类别的问题,这些问题可能会在解决问题时与以后的Apple解决scheme与生成的代码发生冲突。

这是做官方的另外一个方面!

看起来,如果通过将父项设置为子项而将父项与子项联系起来,而不是通过其他方式工作而不会崩溃。

所以如果你这样做:

 [child setParent:parent] 

代替

 [parent setChildObects:child] 

它应该工作,至less它在iOS 7上工作,并没有任何关系的问题。

我有同样的问题,但只有当我尝试了一些与我一直在做的不同的事情。 我看不到子项目的代码,但我会假设它有一个项目的反向链接。 让我们称这个尊敬的链接,“parentItem”,那么最简单的解决scheme是这样的:

 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; 

其效果是它利用了苹果自己的代码,简单而干净。 另外,该集自动添加到,所有观察者都被更新。 没问题。

我刚刚遇到了这个问题,并用比这里列出的更简单的实现来解决这个问题。 我只是简单地使用NSManagedObject上的可用方法来处理不使用子类时的关系。

将实体插入NSOrderedSet关系的示例实现如下所示:

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

这工作得很好,而且是我搬到NSManagedObject子类之前使用的。

在使用XCode 7将项目从Objective-C移植到Swift 2时 ,发生了这个问题。 该项目曾经工作,并有一个很好的理由:我使用MOGenerator有replace方法来解决这个错误。 但并不是所有的方法都需要更换。

因此,这里是一个示例类的完整解决scheme,尽可能依靠默认访问器。

比方说,我们有一个有订单项目的列表

首先,如果你有一对多的关系,那么最简单的做法是:

 item.list = list 

代替

 list.addItemsObject(item) 

现在, 如果这不是一个选项 ,那么你可以这样做:

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

当然,如果你使用的是Objective-C,你可以做同样的事情,因为这是我首先得到的想法:)

我同意这里可能有一个错误。 我已经修改了添加对象> setter的实现来正确地附加到一个NSMutableOrderedSet。

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

将该集重新分配给self.subitems将确保发送Will / DidChangeValue通知。

Leelll,你确定这个自定义的NSMutableOrderedSet值存储在这个设置后,将被CoreData保存到数据库中吗? 我没有检查,但看起来CoreData对NSOrderedSet一无所知,并期望NSSet成为多对多的关系容器。

我想每个人都错过了真正的问题。 它不在访问器方法中,而是在于NSOrderedSet不是NSSet的子类。 所以当-interSectsSet:以一个有序集合作为参数被调用时,它会失败。

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

*** -[NSSet intersectsSet:]: set argument is not an NSSet失败*** -[NSSet intersectsSet:]: set argument is not an NSSet

看起来修复是修改集合运算符的实现,所以他们透明地处理types。 没有理由为什么一个-intersectsSet:应该与一个有序或无序的集合。

exception发生在更改通知中。 大概在处理反向关系的代码中。 因为只有当我设置一个反比关系才会发生。

以下为我做了诡计

 @implementation MF_NSOrderedSetFixes + (void) fixSetMethods { NSArray* classes = [NSArray arrayWithObjects:@"NSSet", @"NSMutableSet", @"NSOrderedSet", @"NSMutableOrderedSet",nil]; [classes 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<count;i++) { if(method_getName(methods[i])==aSel) { method = methods[i]; } } free(methods); } if(!method) { return; } // Get old implementation BoolNSetIMP originalImp = (BoolNSetIMP) method_getImplementation(method); IMP newImp = imp_implementationWithBlock(^BOOL(NSSet *_s, NSSet *otherSet) { if([otherSet isKindOfClass:[NSOrderedSet class]]) { otherSet = [(NSOrderedSet*)otherSet set]; } // Call original implementation return originalImp(_s,aSel,otherSet); }); method_setImplementation(method, newImp); } @end 

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. 在这里输入图像描述

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.

谢谢,

达米安

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

有了这个:

 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!

罗伯特,

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 !