cocoa - 在NSOrderedSet生成的訪問器中引發異常




core-data xcode4 (21)

我使用您的數據模型和我自己的數據模型以不同的名稱複製了您的設置。 在這兩種情況下我都遇到了同樣的錯誤。

看起來像Apple自動生成的代碼中的一個錯誤。

在我的Lion應用程序中,我有這個數據模型:

Item內部的關係subitems 是有序的

Xcode 4.1(build 4B110)為我創建了文件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日)Apple給我寫道: “請使用最新的iOS 10 beta版本驗證此問題,並使用您的結果更新bugreport.apple.com上的錯誤報告。” 。 讓我們希望這是正確的時間:)


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.

謝謝,

Damien


SWIFT中正確答案的更好版本

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

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

我有同樣的問題,但只有當我嘗試了一些與我一直在做的事情不同的東西時。 我看不到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;

其效果是它使用了蘋果自己的代碼,它很簡單,乾淨。 另外,該集自動添加到,並且所有觀察者都被更新。 沒問題。


我剛剛遇到了這個問題,並使用比這裡概述的更簡單的實現來解決這個問題。 我只是簡單地使用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子類之前使用的。


我建議在NSObject中使用訪問器來訪問關係的NSMutableOrderedSet,而不是創建副本。

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

例如, 適用於iOS v5.0核心數據發行說明參考此。

在一個簡短的測試中它在我的應用程序中工作


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

[item addSubitemsObject:subItem];

with this:

item.subitemsObject = subItem;

I solved this problem by set the inverse to No Inverse, I don't know why, Maybe there is Apple Bug.


蘋果公司的文檔To Many Relations說:你應該訪問代理可變集或有序集使用

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

修改此設置將添加或刪除關係到您的託管對象。 使用訪問器訪問可變順序集,無論是使用[]還是使用訪問器。 符號是錯誤的,並會失敗。


我決定通過實施所有必需的方法來改進解決方案:

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


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


我同意這裡可能有一個錯誤。 我已經修改了add對象> 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成為多對多關係容器。


是的,這絕對是一個核心數據錯誤。 我回寫了一個基於ObjC-Runtime的修復程序,但是當時我發現它很快就會被修復。 無論如何,沒有這樣的運氣,所以我把它作為KCOrderedAccessorFix發佈在GitHub上。 解決所有實體上的問題:

[managedObjectModel kc_generateOrderedSetAccessors];

特別是一個實體:

[managedObjectModel kc_generateOrderedSetAccessorsForEntity:entity];

或者只為一個關係:

[managedObjectModel kc_generateOrderedSetAccessorsForRelationship:relationship];

使用XCode 7將項目從Objective-C移植到Swift 2時 ,發生了這個問題。 該項目曾經工作,並有一個很好的理由:我使用MOGenerator,它有替換方法來修復這個bug。 但並非所有方法都需要更換。

所以這裡是一個示例類的完整解決方案,盡可能依靠默認訪問器。

假設我們有一個帶有訂購商品的列表

首先,如果你有一對多的關係,那麼最簡單的做法是:

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,你可以做同樣的事情,因為這是我首先得到這個想法的地方:)


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.


我同意這裡可能有一個錯誤。 我修改了添加對象設置器的實現,以便正確地附加到NSMutableOrderedSet。

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

將該集重新分配給self.subitems將確保發送Will / DidChangeValue通知。


我認為每個人都錯過了真正的問題。 它不在訪問器方法中,而是在於NSOrderedSet不是NSSet的子類。 因此,當-interSectsSet:以有序集作為參數調用時,它會失敗。

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

 [setB intersectsSet:setA];

fails with *** -[NSSet intersectsSet:]: set argument is not an NSSet

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

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

The following did the trick for me

@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 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!


我跟踪了這個錯誤。 它發生在willChangeValueForKey:withSetMutation:usingObjects:

這個呼叫引發了一系列可能難以追踪的通知,當然一個響應者的變化可能會對另一個響應者產生影響,我懷疑蘋果為什麼沒有做任何事情。

但是,它在Set中是可以的,並且它在OrderedSet上只有Set操作發生故障。 這意味著只有四種方法需要修改。 因此,我所做的只是將Set操作轉換為其等效的Array操作。 這些工作完美和最小(但必要)的開銷。

在臨界水平上,這個解決方案確實遭受了一個嚴重的缺陷; 如果您添加對象並且其中一個對像已經存在,那麼它不會被添加或移動到有序列表的後面(我不知道是哪個)。 無論哪種情況,在我們到達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];
    }]];
}

你的第一個謂詞

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"listingID != %@", sessionID];

應該找到屬性listingID不等於sessionID所有記錄(假設listingIDsessionID具有相同的類型)。

如果兩者都是字符串,並且您想要查找其中listingID 不包含字符串sessionID作為子字符串的所有記錄,則此謂詞應該有效:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (listingID CONTAINS %@)", sessionID];

如果字符串比較應該是case和變音不敏感,請使用“CONTAINS [cd]”。

注意 :您可以將屬性名稱指定為參數,但是您必須使用%K而不是%@作為格式:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (%K CONTAINS %@)", @"listingID", sessionID];




cocoa core-data xcode4