Ответ 1
Я воспроизвел вашу установку как с вашей моделью данных, так и с моей собственной версией с разными именами. Я получил ту же ошибку в обоих случаях.
Похож на ошибку в автогенерированном коде Apple.
В моем приложении Lion у меня есть эта модель данных:
Отношение subitems
внутри Item
упорядочено.
Xcode 4.1 (сборка 4B110) создал для меня файл Item.h
, Item.m
, SubItem.h
и SubItem.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
Можете ли вы мне помочь?
Update:
После всего лишь 1,787 дней из моего отчета об ошибке, сегодня (1 августа 2016 года) Apple написала мне это: "Пожалуйста, проверьте эту проблему с последней версией бета-версии iOS 10 и обновите свой отчет об ошибке на странице bugreport.apple.com с результатами.". Пусть надеется, что это подходящее время:)
Я воспроизвел вашу установку как с вашей моделью данных, так и с моей собственной версией с разными именами. Я получил ту же ошибку в обоих случаях.
Похож на ошибку в автогенерированном коде Apple.
Я согласен, что здесь может быть ошибка. Я изменил реализацию установки объекта добавления, чтобы правильно добавить NSMutableOrderedSet.
- (void)addSubitemsObject:(SubItem *)value {
NSMutableOrderedSet* tempSet = [NSMutableOrderedSet orderedSetWithOrderedSet:self.subitems];
[tempSet addObject:value];
self.subitems = tempSet;
}
Переназначение набора в self.subitems гарантирует отправку уведомлений Will/DidChangeValue.
Я решил улучшить решение, выполнив все необходимые методы:
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];
}
}
Да, это определенно ошибка Core Data. Я написал исправление на основе ObjC-Runtime некоторое время назад, но в то время, когда я решил, что скоро будет исправлено. Во всяком случае, нет такой удачи, поэтому я разместил ее на GitHub как KCOrderedAccessorFix. Работайте над проблемой во всех своих сущностях:
[managedObjectModel kc_generateOrderedSetAccessors];
Один объект, в частности:
[managedObjectModel kc_generateOrderedSetAccessorsForEntity:entity];
Или просто для одного отношения:
[managedObjectModel kc_generateOrderedSetAccessorsForRelationship:relationship];
Вместо того, чтобы делать копию, я предлагаю использовать accessor в NSObject для доступа к NSMutableOrderedSet отношений.
- (void)addSubitemsObject:(SubItem *)value {
NSMutableOrderedSet* tempSet = [self mutableOrderedSetValueForKey:@"subitems"];
[tempSet addObject:value];
}
например. Примечания к выпуску основных данных для iOS v5.0 относятся к этому.
В коротком тесте он работал в моем приложении.
Я отслеживал ошибку. Это происходит в willChangeValueForKey:withSetMutation:usingObjects:
.
Этот вызов выдает цепочку уведомлений, которые могут быть трудно отследить, и, конечно, изменения для одного ответчика могут иметь последствия для другого, и я подозреваю, почему Apple ничего не сделала.
Тем не менее, это нормально в Set, и это приводит к сбою в работе только заданий Set на OrderedSet. Это означает, что необходимо изменить только четыре метода. Поэтому все, что я сделал, было преобразование операций Set в их эквивалентные операции массива. Они прекрасно работают и минимальны (но необходимы) накладные расходы.
На критическом уровне это решение действительно страдает от одного критического недостатка; если вы добавляете объекты и один из уже существующих объектов, то он либо не добавлен, либо перемещен в конец упорядоченного списка (я не знаю, какой из них). В любом случае ожидаемый упорядоченный индекс объекта к моменту поступления в 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];
}
Конечно, есть более легкое решение. он выглядит следующим образом:
- (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];
}]];
}
Apple docs To Many Relations говорит: вам нужно получить доступ к прокси-мутируемому набору или упорядоченному набору с помощью
NSMutableOrderedSet * set = [managedObject mutableOrderedSetValueForKey:@"toManyRelation"];
Изменение этого набора добавит или удалит отношения к вашему управляемому объекту. Доступ к изменяемому упорядоченному набору с использованием accessor с помощью [] или. нотация неверна и не будет выполнена.
Получил ту же ошибку, решение @LeeIII работало для меня (спасибо!). Я предлагаю немного изменить его:
Содержимое 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];
Лично я просто заменил вызовы на сгенерированные CoreData методы прямыми вызовами метода, как описано в другом решении @Stephan:
NSMutableOrderedSet* tempSet = [self mutableOrderedSetValueForKey:@"subitems"];
[tempSet addObject:value];
[tempSet addObject:value];
Это устраняет необходимость в категориях, которые могут впоследствии конфликтовать с решением Apple от сгенерированного кода при исправлении ошибки.
У этого есть дополнительный плюс того, чтобы быть официальным способом сделать это!
Похоже, что если вы связали родителя с дочерним элементом, установив родителя в дочерний элемент, а не наоборот, он работает без сбоев.
Итак, если вы выполните:
[child setParent:parent]
вместо
[parent setChildObects:child]
Он должен работать, по крайней мере, он работает на iOS 7 и не имел никаких проблем с этим отношением.
Я согласен, что здесь может быть ошибка. Я изменил реализацию добавления объектa > 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 как много.
У меня была та же проблема, но только когда я пробовал что-то другое, чем то, что я делал. Я не вижу код для subItem, но я предполагаю, что он имеет обратную ссылку на элемент. Позволяет называть эту ссылку reveres "parentItem", тогда самым простым решением является следующее:
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;
Эффект заключается в том, что он использует собственный код Apple, и он прост и чист. Кроме того, набор автоматически добавляется, и все наблюдатели обновляются. Нет проблем.
Я просто свалил эту проблему и решил ее, используя гораздо более простую реализацию, чем другие, описанные здесь. Я просто использую методы, доступные в NSManagedObject
для работы с отношениями, когда не используются подклассы.
Пример реализации для вставки объекта в отношение NSOrderedSet
будет выглядеть так:
- (void)addAddress:(Address *)address
{
if ([self.addresses containsObject:address]) {
return;
}
// Use NSManagedObject methods for inserting an object
[[self mutableOrderedSetValueForKey:@"addresses"] addObject:address];
}
Это работает отлично, и это то, что я использовал до того, как перешел в подклассы NSManagedObject
.
Эта проблема возникла при переносе проекта с Objective-C на Swift 2 с XCode 7. Этот проект работал, и по уважительной причине: я использовал MOGenerator, у которого были методы замены, чтобы исправить эту ошибку. Но не все методы требуют замены.
Итак, вот полное решение с примерным классом, максимально использующее аксессоры по умолчанию.
Скажем, у нас есть список с упорядоченными элементами
Сначала быстрый выигрыш, если у вас есть отношение "один/ко-многим", проще всего просто:
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 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, вы можете сделать то же самое, так как именно здесь я получил эту идею:)
Я думаю, что у всех отсутствует реальная проблема. Это не в методах доступа, а скорее в том, что 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
Похоже, что исправление заключается в том, чтобы изменить реализацию операторов set, чтобы они прозрачно обрабатывали типы. Нет причин, по которым -interSectsSet:
должен работать с упорядоченным или неупорядоченным множеством.
Исключение происходит в уведомлении об изменении. Предположительно в коде, который обрабатывает обратную связь. Так как это происходит, если я устанавливаю обратную связь.
Следующее сделало трюк для меня
@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
У меня проблема только в Swift (Xcode 6.1.1).
Ответ был НЕ КОДИРОВАТЬ ЛЮБОЙ МЕТОД ИЛИ ДОПОЛНИТЕЛЬНЫЕ ВЕЩИ в подклассах NSManagedObject. Я думаю, что это ошибка компилятора. Очень странная ошибка.
Надеюсь, что это поможет.
Я решил эту проблему, установив инверсию в No Inverse, я не знаю, почему, Возможно, есть Apple Bug.
У меня такая же ситуация с элементом, называемым "сигналы", а не "подэлементы". Решение с tempset работает в моем тестировании. Кроме того, у меня возникла проблема с методом removeSignals:. Это переопределение, похоже, работает:
- (void)removeSignals:(NSOrderedSet *)values {
NSMutableOrderedSet* tempset = [NSMutableOrderedSet orderedSetWithOrderedSet:self.signals];
for (Signal* aSignal in values) {
[tempset removeObject:aSignal];
}
self.signals = tempset;
}
Если есть лучший способ сделать это, пожалуйста, дайте мне знать. Входные значения моих значений не превышают 10 -20 элементов, поэтому производительность не вызывает большого беспокойства. Тем не менее, пожалуйста, укажите на что-то важное.
Спасибо,
Damien
Я нашел исправление для этой ошибки, которая работает для меня. Я просто заменяю это:
[item addSubitemsObject:subItem];
с этим:
item.subitemsObject = subItem;
Я нашел этот вопрос, перейдя по ссылке на сообщение об ошибке, и просто хотел указать, что я столкнулся с этой ошибкой несколько иначе (не используя упорядоченные множества). Это не совсем ответ на данный вопрос, но я отправляю его здесь на всякий случай, когда это полезно для всех, кто сталкивается с этим вопросом во время поиска.
Я добавлял новую версию модели и добавлял некоторые отношения к существующим моделям и сам определял методы add * Object в файле заголовка. Когда я попытался их вызвать, я получил ошибку выше.
После просмотра моих моделей я понял, что я глупо забыл проверить флажок "Множество отношений".
Итак, если вы работаете с этим, и вы не используете упорядоченные наборы, дважды проверьте свою модель.
Я нашел использование метода LeeIII, но при профилировании выяснилось, что он был крайне медленным. Для анализа 1000 предметов потребовалось 15 секунд. Комментируя код для добавления отношения, получилось 15 секунд до 2 секунд.
Мое обходное решение (которое быстрее, но гораздо более уродливое) включает создание временного изменяемого массива, а затем копирование в упорядоченное множество, когда all выполняется синтаксический анализ. (это только выигрыш в производительности, если вы собираетесь добавить много отношений).
@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;
}
}
Я надеюсь, что это поможет кому-то еще!
Роберт
Я согласен, что ваш ответ будет работать для этого, но имейте в виду, что существует автоматически созданный метод для добавления целого набора значений в отношения. Документация Apple (как показано здесь в разделе "Отношения со многими" или здесь в разделе "Индивидуальные методы доступа к деталям" ) реализует их следующим образом:
- (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];
}
Вы можете легко скомпилировать свой набор отношений вне основных данных, а затем добавить их все сразу, используя этот метод. Это может быть менее уродливым, чем предложенный вами метод;)
Я уверен, что наконец-то исправлено в iOS 10 beta 6!