cocoa - تم طرح استثناء في NSOrderedSet الموصلات




core-data xcode4 (21)

في تطبيق Lion ، لدي نموذج البيانات هذا:

يتم ترتيب Item subitems للعلاقة داخل Item .

Xcode 4.1 (build 4B110) قام بإنشاء الملف Item.h و Item.m و SubItem.h و SubItem.h .

هنا هو المحتوى (autogenerated) من 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

وهنا هو المحتوى (autogenerated) من 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

هل بإمكانك مساعدتي؟

تحديث:

بعد 1787 يومًا فقط من تقرير الأخطاء ، واليوم (1 آب 2016) كتبت لي Apple هذا: "الرجاء التحقق من هذه المشكلة باستخدام أحدث إصدار من نظام التشغيل iOS 10 وتحديث تقرير الأخطاء على bugreport.apple.com مع نتائجك." . دعونا نأمل أن هذا هو الوقت المناسب :)


Answers

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


بدلاً من عمل نسخة أقترح استخدام أداة accessor في NSObject للوصول إلى NSMutableOrderedSet للعلاقات.

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

على سبيل المثال ، تشير ملاحظات إصدار البيانات الأساسية لنظام التشغيل iOS v5.0 إلى هذا.

في اختبار قصير عملت في طلبي.


يقول Apple Docs To Many Relations : يجب عليك الوصول إلى مجموعة الوكيل القابلة للتغيير أو مجموعة مرتبة باستخدام

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

سيؤدي تعديل هذه المجموعة إلى إضافة أو إزالة العلاقات إلى الكائن المُدار. الوصول إلى مجموعة الأوامر القابلة للتغيير التي تم إعدادها باستخدام الملحق سواءً كان مع [] أو. الترميز خطأ وسيفشل.


لقد تتبعت الخطأ. يحدث في willChangeValueForKey:withSetMutation:usingObjects:

تقوم هذه المكالمة ببدء سلسلة من الإشعارات التي قد يكون من الصعب تتبعها ، وبالطبع قد يكون للتغييرات في أحد المستجيبين آثار على أخرى ، والتي أظن أن أبل لم تفعل شيئًا.

ومع ذلك ، فإنه على ما يرام في مجموعة والعمليات فقط تعيين على OrderedSet التي عطل. وهذا يعني أن هناك أربع طرق فقط تحتاج إلى تغيير. لذلك ، كل ما فعلته هو تحويل عمليات 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];
    }]];
}

أوافق على احتمال وجود خطأ هنا. لقد قمت بتعديل تطبيق إضافة كائن> 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 كعلاقة علاقة كثيرة.


أعتقد أن الجميع يفتقدون المشكلة الحقيقية. ليس في أساليب accessor ولكن بدلاً من ذلك في حقيقة أن 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 a fix for this bug that works for me. I just replace this:

[item addSubitemsObject:subItem];

with this:

item.subitemsObject = subItem;

إذا كنت تستخدم mogenerator ، ثم بدلا من

[parentObject add<Child>sObject:childObject];

ببساطة استخدام:

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

Robert,

I agree your answer will work for this, but keep in mind that there is an automatically created method for adding a whole set of values to a relationship already. Apple's Documentation ( as seen here under the "To-many Relationships" section or here under the "Custom To-Many Relationship Accessor Methods" section) implements them this way:

- (void)addEmployees:(NSSet *)value
{
[self willChangeValueForKey:@"employees"
      withSetMutation:NSKeyValueUnionSetMutation
      usingObjects:value];
[[self primitiveEmployees] unionSet:value];
[self didChangeValueForKey:@"employees"
      withSetMutation:NSKeyValueUnionSetMutation
      usingObjects:value];
}

- (void)removeEmployees:(NSSet *)value
{
[self willChangeValueForKey:@"employees"
      withSetMutation:NSKeyValueMinusSetMutation
      usingObjects:value];
[[self primitiveEmployees] minusSet:value];
[self didChangeValueForKey:@"employees"
      withSetMutation:NSKeyValueMinusSetMutation
      usingObjects:value];
}

يمكنك بسهولة تجميع مجموعة العلاقات الخاصة بك خارج البيانات الأساسية ثم إضافتها كلها مرة واحدة باستخدام هذه الطريقة. قد يكون قبيحًا أقل من الطريقة التي اقترحتها ؛)


حدثت هذه المشكلة لي أثناء ترحيل مشروع من 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'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 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.


أوافق على أنه قد يكون هناك خلل هنا. لقد قمت بتعديل تطبيق إضافة كائن إضافة إلحاق بشكل صحيح إلى NSMutableOrderedSet.

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

سيؤدي تعيين المجموعة إلى self.subitems إلى ضمان إرسال إعلامات Will / DidChangeValue.


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


أنا شخصياً قد استبدلت للتو مكالمات إلى الأساليب التي تم إنشاؤها CoreData مع المكالمات المباشرة إلى الأسلوب كما هو موضح في حل آخر بواسطة Stepep:

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

يؤدي ذلك إلى إزالة الحاجة إلى الفئات التي قد تتعارض لاحقًا مع حل من Apple إلى الشفرة التي تم إنشاؤها عند إصلاح الخطأ.

هذا إضافة إلى كونها الطريقة الرسمية للقيام بذلك!


لقد قررت تحسين الحل من خلال تنفيذ جميع الطرق المطلوبة:

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

يبدو أنه إذا قمت بربط الوالد مع الطفل عن طريق وضع الوالد على الطفل وليس العكس ، فإنه يعمل دون أن ينهار.

لذلك إذا فعلت:

[child setParent:parent]

بدلا من

[parent setChildObects:child]

يجب أن يعمل ، على الأقل أنه يعمل على iOS 7 ولم يكن لديه أي مشاكل في العلاقة.


نعم ، هذا بالتأكيد خطأ في البيانات الأساسية. كتبت في وقت سابق على أساس ObjC-Runtime الإصلاح ، ولكن في الوقت الذي برزت أنه سيتم إصلاحه قريبا. على أي حال ، لا يوجد مثل هذا الحظ ، لذلك أنا نشرت على GitHub كما KCOrderedAccessorFix . اعمل على حل المشكلة في جميع الكيانات:

[managedObjectModel kc_generateOrderedSetAccessors];

كيان واحد على وجه الخصوص:

[managedObjectModel kc_generateOrderedSetAccessorsForEntity:entity];

أو فقط لعلاقة واحدة:

[managedObjectModel kc_generateOrderedSetAccessorsForRelationship:relationship];

 var context:NSManagedObjectContext = appDel.managedObjectContext!

 var en = NSEntityDescription.entityForName("ENTITIES_NAME", inManagedObjectContext: context)

 let batchUpdateRequest = NSBatchUpdateRequest(entity: en!)
            batchUpdateRequest.resultType = NSBatchUpdateRequestResultType.UpdatedObjectIDsResultType
            batchUpdateRequest.propertiesToUpdate = ["OBJECT_KEY": "NEWVALUE"]
            var batchUpdateRequestError: NSError?
            context.executeRequest(batchUpdateRequest, error:&batchUpdateRequestError)
            if let error = batchUpdateRequestError {println("error")}

حظا طيبا وفقك الله





cocoa core-data xcode4