web-dev-qa-db-ja.com

NSOrderedSetで生成されたアクセサでスローされた例外

Lionアプリでは、次のデータモデルを使用しています。

enter image description here

subitems内の関係Item順序付け済み

Xcode 4.1(ビルド4B110)は、ファイルItem.hItem.mSubItem.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

手伝って頂けますか?

更新:

バグレポートからわずか1,787日後、今日(2016年8月1日)Appleから次のように書かれました: "最新のiOS 10ベータビルドおよびアップデートでこの問題を確認してくださいbugreport.Apple.comでのバグレポートと結果。 "。これが適切な時期であることを望みましょう:)

363
Dev

データモデルと、独自の名前の異なるモデルの両方でセットアップを再現しました。どちらの場合も同じエラーが発生しました。

Appleの自動生成コードのバグのように見えます。

263
TechZen

ここにバグがある可能性があることに同意します。 NSMutableOrderedSetに正しく追加するように、オブジェクト追加セッターの実装を変更しました。

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

セットをself.subitemsに再割り当てすると、Will/DidChangeValue通知が確実に送信されます。

243
InitJason

必要なすべてのメソッドを実装することにより、ソリューションを改善することにしました。

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

はい、これは間違いなくコアデータのバグです。しばらく前に、ObjCランタイムベースの修正プログラムを作成しましたが、その時点ですぐに修正されると考えていました。とにかく、そのような幸運はないので、GitHubに KCOrderedAccessorFix として投稿しました。すべてのエンティティの問題を回避します。

[managedObjectModel kc_generateOrderedSetAccessors];

特に1つのエンティティ:

[managedObjectModel kc_generateOrderedSetAccessorsForEntity:entity];

または、1つの関係についてのみ:

[managedObjectModel kc_generateOrderedSetAccessorsForRelationship:relationship];
38
Sterling Archer

コピーを作成する代わりに、NSObjectのアクセサーを使用して、リレーションシップのNSMutableOrderedSetにアクセスすることをお勧めします。

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

例えば iOS v5.0のコアデータリリースノート これを参照してください。

短いテストでは、私のアプリケーションで機能しました。

32
Stephan

バグを追跡しました。 willChangeValueForKey:withSetMutation:usingObjects:で発生します。

この呼び出しは、追跡が困難な可能性のある一連の通知を開始し、もちろん、あるレスポンダーへの変更が別のレスポンダーに影響を与える可能性があるため、Appleが何もしなかったと思われます。

ただし、Setでは問題なく、OrderedSetでのSet操作のみが誤動作します。つまり、変更する必要があるメソッドは4つだけです。したがって、設定操作を同等の配列操作に変換するだけでした。これらは完全に機能し、最小限の(ただし必要な)オーバーヘッドをもたらします。

重大なレベルでは、このソリューションには1つの重大な欠陥があります。オブジェクトを追加するときに、オブジェクトの1つが既に存在する場合、そのオブジェクトは追加されないか、順序付きリストの後ろに移動します(どちらがわかりません)。いずれの場合も、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];
    }]];
}
17
Owen Godfrey

Apple Docs To Many Relationsは、次を使用して、プロキシの可変セットまたは順序付きセットにアクセスする必要があります

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

このセットを変更すると、管理オブジェクトに関係が追加または削除されます。 []または。表記が間違っており、失敗します。

10
Nicolas Manzini

同じエラーを受け取った、@ LeeIIIソリューションは私のために働いた(ありがとう!)。少し変更することをお勧めします。

  • objective-Cカテゴリを使用して新しいメソッドを保存します(したがって、Itemが再度生成されてもメソッドを失うことはありません)
  • 既に可変セットがあるかどうかを確認します

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
9
Danik

発電機を使用している場合、代わりに

[parentObject add<Child>sObject:childObject];

単に使用します:

[[parent object <child>sSet] addObject:childObject];
8
Καrτhικ

個人的には、@ Stephanによる別のソリューションで概説されているように、CoreDataで生成されたメソッドの呼び出しをメソッドの直接呼び出しに置き換えました。

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

これにより、バグが修正されたときに、生成されたコードに対するAppleからのソリューションと後で競合する可能性のあるカテゴリの必要性がなくなります。

これには、公式の方法であるという利点が追加されています!

7
Grouchal

親を子に設定して親を子にリンクすると、クラッシュせずに動作します。

だから:

[child setParent:parent]

代わりに

[parent setChildObects:child]

動作するはずです。少なくともiOS 7で動作し、関係に問題はありませんでした。

5
Cata

この問題は、Objective-CからSwift 2 with XCode 7にプロジェクトを移行しているときに発生しました。このプロジェクトは以前は機能していましたが、それには正当な理由があります。このバグを修正するための代替方法を備えたMOGeneratorを使用していました。しかし、すべてのメソッドが置換を必要とするわけではありません。

したがって、可能な限りデフォルトのアクセサーに依存する、サンプルクラスを使用した完全なソリューションを次に示します。

注文したアイテムのリストがあるとしましょう

最初にquick win 1対多の関係がある場合、最も簡単な方法は次のとおりです。

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を使用している場合は、まったく同じことを行うことができます。最初にアイデアを得た場所だからです:)

3
Nycen

私はこの問題に反則し、ここで説明した他の実装よりもはるかに単純な実装を使用して解決しました。サブクラスを使用しないときに関係を処理するために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サブクラスに移動する前に使用していたものです。

3
Mic Pringle

ここにバグがあるかもしれないことに同意します。 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を多対多のリレーションシップコンテナとして期待しているようです。

3
DisableR

私は同じ問題を抱えていましたが、自分がやっていたこととは異なる何かを試したときだけです。 subItemのコードは表示されませんが、itemへの逆方向リンクがあると仮定します。この敬称リンクを「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独自のコードを利用し、シンプルでクリーンなことです。さらに、セットが自動的に追加され、すべてのオブザーバーが更新されます。問題ない。

3
Owen Godfrey

この問題を解決するには、逆を[逆なし]に設定しました。理由はわかりませんが、Appleバグがあるかもしれません。 enter image description here

2
LevinYan

Swift(Xcode 6.1.1)で問題が発生しました。

答えは、NSManagedObjectサブクラスでメソッドOR追加事項をコーディングしないでくださいでした。これはコンピレーターの間違いだと思う。非常に奇妙なバグ..

それが役に立てば幸い ..

2
lobodart

誰もが本当の問題を見逃していると思います。アクセサメソッドではなく、NSOrderedSetNSSetのサブクラスではないという事実です。したがって、-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
2
Entropy

「サブアイテム」ではなく「シグナル」というアイテムでも同じ状況になります。 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項目を超えないので、パフォーマンスはそれほど気になりません-それにもかかわらず、関連する何かを指摘してください。

おかげで、

ダミアン

1

このバグの修正が見つかりました。私はこれを置き換えるだけです:

[item addSubitemsObject:subItem];

これとともに:

item.subitemsObject = subItem;
1
Bimawa

エラーメッセージをグーグルで調べてこの質問を見つけましたが、ちょっと違う方法でこのエラーに遭遇したことを指摘したかったのです(順序付きセットを使用していません)。これは、与えられた質問に対する回答ではありませんが、検索中にこの質問に出くわした他の人に役立つ場合に備えて、ここに投稿しています。

新しいモデルバージョンを追加し、既存のモデルにいくつかの関係を追加し、ヘッダーファイルでadd * Objectメソッドを自分で定義しました。それらを呼び出そうとすると、上記のエラーが発生しました。

モデルを確認した後、「対多リレーションシップ」チェックボックスをチェックするのを愚かに忘れていたことに気付きました。

したがって、これに遭遇していて、順序付きセットを使用していない場合は、モデルを再確認してください。

1
BenV

最終的には間違いなく iOS 10ベータ6で修正済み

0
an0

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

これが他の人の助けになることを願っています!

0
Robert

Swiftの正解のより良いバージョン

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

tempSet.add(newItem)
parent!.subItems = tempSet
0
emreoktem

ロバート、

あなたの答えがこれでうまくいくことに同意しますが、すでに値のセット全体を関係に追加するための自動的に作成されたメソッドがあることに留意してください。 Appleのドキュメント( こちら参照 "To-many Relationships"セクションの下、または here "Custom To-Many Relationship Accessor Methods"セクションの下)は、次のように実装しています。

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

コアデータ以外の関係のセットを簡単にコンパイルし、このメソッドを使用してそれらを一度にすべて追加できます。あなたが提案した方法よりも少ないかもしれませんugい;)

0
JiuJitsuCoder