มีข้อผิดพลาดเกิดขึ้นใน NSOrderedSet ที่สร้างขึ้น accessors


364

ในแอป Lion ของฉันฉันมีโมเดลข้อมูลนี้:

ป้อนคำอธิบายรูปภาพที่นี่

ความสัมพันธ์subitemsภายในได้รับคำสั่งItem

Xcode 4.1 (สร้าง 4B110) ได้สร้างสำหรับฉันไฟล์Item.h, Item.m, และSubItem.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 วันจากรายงานข้อผิดพลาดของฉันวันนี้ (1 สิงหาคม 2016) Apple เขียนถึงฉัน: "โปรดยืนยันปัญหานี้ด้วยการสร้าง iOS 10 เบต้าล่าสุดและอัปเดตรายงานข้อผิดพลาดของคุณที่ bugreport.apple.com พร้อมผลลัพธ์ของคุณ" . หวังว่านี่เป็นเวลาที่เหมาะสม :)


5
ฉันเห็นปัญหาเดียวกัน หวังว่าจะได้รับการแก้ไขในไม่ช้า แม้ว่าการใช้ชุดคำสั่งที่เปลี่ยนแปลงไม่ได้โดยตรงนั้นเป็นวิธีแก้ปัญหาที่ง่ายในขณะนั้น หมายเหตุ: ฉันกำลังใช้ mogenerator แต่ฉันคิดว่ามันใช้ตัวกำเนิดแอปเปิ้ลตัวเดียวกันภายในรหัสนี้ที่สร้างขึ้น
Chad Podoski

12
เกือบ 2 ปีแล้ว! คุณจะแก้ไขใน iOS 7, Apple หรือไม่ —— ฉันแค่ต้องการแบ่งปันกับผู้ที่สงสัยว่าจุดบกพร่องนี้ยังอยู่ที่นั่นหรือไม่: "ใช่แล้ว"
an0

1
ตอนนี้ใกล้จะถึงสองปีแล้วนี่ยังคงเป็นปัญหาในตัวอย่างของนักพัฒนาซอฟต์แวร์ xcode 5 ทั้งหมด
Korvin Szanto

2
คุณยังเห็นปัญหาอยู่หรือไม่หากคุณใช้อุปกรณ์เสริม KVC ที่เหมาะสม (เช่นmutableOrderedSetValueForKey:)
ระงับ

3
ดูเหมือนจะยังคงมีปัญหาใน Mavericks
ทิม

คำตอบ:


263

ฉันทำซ้ำการตั้งค่าของคุณทั้งในรูปแบบข้อมูลของคุณและหนึ่งในของฉันเองที่มีชื่อแตกต่างกัน ฉันได้รับข้อผิดพลาดเดียวกันทั้งสองกรณี

ดูเหมือนว่าบั๊กในรหัสที่สร้างอัตโนมัติของ Apple


60
ID ข้อผิดพลาดคือ 10114310 ซึ่งมีการรายงานในวันที่ 13 ก.ย. 2554 แต่วันนี้ (15 มกราคม 2555) ยังคงเป็น "เปิด" มันเหลือเชื่อเมื่อพิจารณาจำนวนคนที่มีปัญหาเดียวกัน
Dev

14
อัปเดต: วันนี้ (11 พฤษภาคม 2012) ข้อผิดพลาด # 10114310 ยังคงเปิดอยู่ 241 วันหลังจากรายงานของฉัน (13 กันยายน 2011) เหลือเชื่อ.
Dev

23
ฉันเพิ่งนำเรื่องนี้มาพร้อมกับวิศวกรของ Apple ในช่วงหนึ่งของการประชุม CoreData Lab ที่ WWDC พวกเขารับทราบปัญหาและเป็นข้อผิดพลาดของแท้และจากสิ่งที่ฉันเห็นว่ามีสถานะ "วิกฤติ" แต่แน่นอนไม่มีสัญญาว่าเมื่อใดที่พวกเขาจะแก้ไข ฉันไม่คิดว่ามันจะได้รับการแก้ไขใน iOS6 / Mountain Lion ฉันคิดว่ามันคงจะดีถ้าจะทำสำเนาเรดาร์นี้ต่อไป ขณะนี้มันมีประมาณ 25 ครั้งยิ่งมากยิ่งดี!
DaGaMs

40
เพิ่งตรวจสอบวันนี้มันยังอยู่ใน iOS 7 GM / OMG! ฉันไม่อยากจะเชื่อเลย…
an0

79
อัปเดต: 797 วัน, iOS ใหม่ 2 เวอร์ชันหลักและเวอร์ชัน Xcode นับไม่ถ้วนได้ผ่านไปแล้วตั้งแต่ฉันเติมข้อผิดพลาด # 10114310 และยังคงเป็น "เปิด" เหลือเชื่อ.
Dev

244

ฉันยอมรับว่าอาจมีข้อผิดพลาดที่นี่ ฉันได้ปรับใช้งานการเพิ่มตัวตั้งค่าวัตถุเพื่อผนวกอย่างถูกต้องกับ NSMutableOrderedSet

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

การกำหนดชุดให้เป็น self.subitems อีกครั้งจะทำให้มั่นใจได้ว่าจะส่งการแจ้งเตือน Will / DidChangeValue


ข้อมูลโค้ดของคุณเป็นสิ่งที่ฉันต้องการเพื่อแก้ไขปัญหานี้ หวังว่า Apple จะแก้ไขปัญหาได้ในที่สุด แต่จนถึงตอนนี้ฉันยังไม่เห็นปัญหาใด ๆ เกี่ยวกับการใช้วิธีการของคุณ
Christopher Hujanen

ฉันได้รับข้อผิดพลาดนี้เมื่อฉันพยายามที่จะใช้วิธีแก้ปัญหานี้ .. [__NSArrayI isEqualToSet:]: ตัวเลือกที่ไม่รู้จักส่งไปยังอินสแตนซ์ ... นี่มักจะมาจากรายการที่เผยแพร่ แต่ไม่พบว่ามีใครทำงานอยู่ที่ไหน ลงในนี้
DerekH

@DerekH isEqualToSet เป็นวิธีการเดียวที่ NSSet มีดังนั้นฉันเดาว่าคุณได้แปลงสร้างหรือปฏิบัติกับตัวชี้เป็น NSArray ก่อนส่งกลับไปยัง NSManagedObject ซึ่งควรมีเหตุผลถ้ามีการเรียก isEqualToOrderedSet ที่จะเปลี่ยนแปลงหรือถูกทิ้งไว้ตามที่เป็นอยู่
InitJason

3
@ MarkAmery ทดสอบแล้ว ตรวจสอบแล้ว dynamic setter self.subitems จะส่งการแจ้งเตือน ดังนั้นวิธีแก้ไขปัญหาของ JLust นั้นถูกต้อง
bernstein

3
นี่เป็นคำตอบที่ดี แต่ไม่มีประสิทธิภาพ คุณคัดลอกทั้งชุดสั่งแก้ไขและคัดลอกกลับ เอฟเฟกต์ไม่ได้เป็นเพียงแค่ชุดที่สั่งซื้อเท่านั้น แต่การแจ้งเตือนจะถูกส่งออกไปว่าทุกครั้งที่มีการเปลี่ยนแปลงชุดที่สั่งซื้อเนื้อหาทั้งหมดจะเปลี่ยนไป! หากชุดที่สั่งซื้อนี้ถูกใช้สำหรับ UITable เช่นนี้อาจมีผลกระทบที่ร้ายแรงสำหรับการอัปเดต ฉันได้อธิบายไว้ในวิธีการแก้ปัญหาของฉันตรงที่ข้อผิดพลาดมาจากและฉันได้แสดงวิธีที่มีประสิทธิภาพมากขึ้นสำหรับการข้ามข้อผิดพลาด
โอเว่นก็อดฟรีย์

111

ฉันตัดสินใจที่จะปรับปรุงโซลูชันโดยใช้วิธีการที่จำเป็นทั้งหมด:

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

1
ประเภทการชนคืออะไร 'removeObjectFromSubitemsAtIndex' ไม่ได้ลบรายการย่อยเหล่านี้พวกเขายังคงอยู่ในที่เก็บข้อมูลของคุณมันเป็นเพียงวิธีลบความสัมพันธ์ระหว่างวัตถุ
Dmitry Makarenko

2
kItemsKey เป็นค่าคงที่ซึ่งถูกเพิ่มเข้ามาเพื่อความสะดวกในการเรียกใช้เมธอด KVO เป็นชื่อของความสัมพันธ์ที่สั่งซื้อซึ่งคุณเขียนวิธีการ
Dmitry Makarenko

1
นั่นคือสิ่งที่ฉันคิดว่ามันเป็น ขอบคุณ แต่ปัญหาของฉันคือข้อมูลไม่ถูกบันทึกลงในฐานข้อมูลโดยใช้วิธีการเหล่านี้
Bagusflyer

4
!!!!!!!!! เพียงแค่คัดลอกโค้ดและเปลี่ยนชื่อเมธอดมันทำงานได้อย่างสมบูรณ์แบบ !!! นี่คือคำตอบที่เร็วที่สุด
flypig

1
นี่ยอดเยี่ยม แต่การสร้างสำเนาชั่วคราวของชุดสั่งซื้อนั้นไม่จำเป็น ผู้ร้ายคือwillChangeValueForKey:withSetMutation:usingObjectsสิ่งที่คุณหลีกเลี่ยงได้สำเร็จ หลังจากนั้นเพียงใช้[[self primitiveValueForKey:ChildrenKey] unionOrderedSet:values]หรือ[[self primitiveValueForKey:ChildrenKey] minusOrderedSet:values]ตามความเหมาะสม ดูคำตอบของฉันสำหรับรายละเอียด
โอเว่นก็อดฟรีย์

38

ใช่นี่เป็นข้อผิดพลาดของ Core Data ฉันเขียนการแก้ไขตาม ObjC-Runtime สักพักแล้ว แต่ในเวลานั้นฉันคิดว่ามันจะได้รับการแก้ไขในไม่ช้า อย่างไรก็ตามไม่มีโชคเช่นดังนั้นผมโพสต์ขึ้นบน GitHub เป็นKCOrderedAccessorFix แก้ไขปัญหาเกี่ยวกับเอนทิตีทั้งหมดของคุณ:

[managedObjectModel kc_generateOrderedSetAccessors];

โดยเฉพาะอย่างยิ่งหนึ่งเอนทิตี:

[managedObjectModel kc_generateOrderedSetAccessorsForEntity:entity];

หรือเพียงแค่หนึ่งความสัมพันธ์:

[managedObjectModel kc_generateOrderedSetAccessorsForRelationship:relationship];

ฉันสงสัยว่ามันจะขัดแย้งกับการแก้ไขจริงจาก Apple หรือไม่?
tia

3
สิ่งนี้ไม่ควรขัดแย้งกับการแก้ไขของ Apple เนื่องจากมีวัตถุประสงค์เพื่อแทนที่การใช้งานของ Apple ไม่ว่าจะเกิดอะไรขึ้น เมื่อ / ถ้า Apple ได้รับการแก้ไขจริง ๆ แล้วฉันอาจจะเพิ่ม- (BOOL)kc_needsOrderedSetAccessorFix;หรือสิ่งที่ตรวจสอบรุ่น Foundation / iOS
Sterling Archer

2
มี KCOrderedAccessorFix.podspec อยู่แล้วใน repo หลักของ CocoaPods ดังนั้นเพื่อเชื่อมโยงสิ่งนี้เข้ากับโครงการของคุณคุณสามารถเพิ่ม "pod 'KCOrderedAccessorFix'" ลงใน Podfile ของคุณได้
Anton Matosov

มีปัญหาบางอย่างกับ iOS 8 (ลายเซ็นวิธีการที่ไม่ถูกต้องobjc_msg_send)
NSTJ

ใน iOS9 มันใช้งานได้ดีมาก! นี่เป็นทางออกที่ดีที่สุดไม่จำเป็นต้องเปลี่ยนอะไรในรหัสของคุณ!
Borzh

32

แทนที่จะทำสำเนาผมแนะนำให้ใช้ accessor ใน NSObject เพื่อเข้าถึง NSMutableOrderedSet ของความสัมพันธ์

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

เช่นหมายเหตุการเผยแพร่ข้อมูล Core สำหรับ iOS v5.0อ้างอิงถึงสิ่งนี้

ในการทดสอบสั้น ๆ มันทำงานในใบสมัครของฉัน


1
ไม่สามารถกำหนดค่าสตริงตามตัวอักษรได้อย่างง่ายดาย คอมไพเลอร์สามารถพิมพ์ check self.subitems ถ้าคุณใช้รหัส
logancautrell

1
@logancautrell ใช่ถูกต้อง ขึ้นอยู่กับลำดับความสำคัญของกรณีการใช้งานเฉพาะ โดยทั่วไปฉันมุ่งเน้นไปที่การประหยัดทรัพยากรโดยเฉพาะอย่างยิ่งในกรณีนี้เพราะนี่เป็นเพียงวิธีแก้ปัญหา
เตฟาน

2
สายอักขระตัวอักษรอาจถูกแทนที่ด้วยNSStringFromSelector(@selector(subitems))แม้ว่า :)
แจ็ค

17

ฉันติดตามข้อผิดพลาด willChangeValueForKey:withSetMutation:usingObjects:มันเกิดขึ้นใน

การโทรนี้เริ่มต้นการแจ้งเตือนซึ่งอาจติดตามได้ยากและแน่นอนว่าการเปลี่ยนแปลงผู้ตอบกลับหนึ่งคนอาจมีผลกระทบต่อผู้อื่นซึ่งฉันสงสัยว่าเป็นเพราะเหตุใด Apple จึงไม่ทำอะไรเลย

อย่างไรก็ตามมันก็โอเคในชุดและมันเป็นเพียงการดำเนินการตั้งค่าบน OrderedSet ที่ทำงานผิดปกติ นั่นหมายความว่ามีเพียงสี่วิธีที่ต้องแก้ไข ดังนั้นสิ่งที่ฉันทำคือเปลี่ยนการตั้งค่าให้เป็นการดำเนินการ 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];
    }]];
}

น่าเสียดายที่คนอื่นมองข้ามคำตอบนี้ดูเหมือนจะเป็นทางออกที่ดีที่สุด
George

โซลูชันนี้มีประสิทธิภาพที่ดีขึ้นกว่าชุดที่ใช้ OrderSetWithOrderedSet เพื่อสร้างชุดโลคัล นั่นมีค่าใช้จ่ายมากเมื่อคุณมีชุดข้อมูลขนาดใหญ่ โซลูชันที่ง่ายขึ้นดูเหมือนจะเป็นรุ่นที่ได้รับการปรับสภาพใหม่ของโซลูชันเริ่มต้นด้วยวิธีที่ไม่แสดง
David Pettigrew

1
ฉันยังคงเห็นความผิดพลาดใน addChildren: *** ยกเลิกแอปเนื่องจากการยกเว้น uncaught 'NSInvalidArgumentException' เหตุผล '- [insertTrackpoints TrackHistory: atIndexes:]: เลือกไม่รู้จักส่งไปเช่น 0x1702b1b20'
วิคเตอร์ Bogdan

@OwenGodfrey เพื่อการแก้ปัญหาที่ง่ายขึ้นคุณจะใช้วิธีการเหล่านี้ที่ไหน? ฉันได้รับการยกเว้น: [Parent insertObject: inChildrenAtIndex:] ตัวเลือกที่ไม่รู้จักถูกส่งไปยังอินสแตนซ์ 0x6180000ac480
Dalmazio

ตัวแปรของคุณคือ "ผู้ปกครอง" ที่มีทุน "P" หรือไม่? หมายความว่าคุณกำลังเรียกคลาส "ผู้ปกครอง" หรือคุณมีตัวแปรอินสแตนซ์ชื่อ "ผู้ปกครอง" หรือไม่? หากคลาสของฉันคือผู้ปกครองฉันใช้วิธีการนี้ที่ด้านล่างของผู้ปกครอง แต่คุณจะต้องเรียกมันในอินสแตนซ์ซึ่งมีแนวโน้มที่จะมีชื่อว่า "ผู้ปกครอง" ที่มีตัวพิมพ์เล็ก "p" เพราะนี่ไม่ใช่วิธีการเรียน .
โอเว่นก็อดฟรีย์

10

เอกสารแอปเปิ้ลกับความสัมพันธ์หลายคนพูดว่า: คุณควรเข้าถึงการตั้งค่าพร็อกซี่ที่ไม่แน่นอนหรือสั่งตั้งค่าการใช้

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

การแก้ไขชุดนี้จะเพิ่มหรือลบความสัมพันธ์กับวัตถุที่มีการจัดการของคุณ การเข้าถึงชุดที่เรียงลำดับไม่แน่นอนโดยใช้ accessor ไม่ว่าจะด้วย [] หรือ สัญกรณ์ผิดและจะล้มเหลว


3
เพื่อความเป็นธรรมเอกสารดังกล่าวยังกล่าวอีกว่า: "หรือหนึ่งในวิธีการสร้างความสัมพันธ์ที่สร้างขึ้นโดยอัตโนมัติ (ดูวิธีการเข้าถึงของผู้สร้างแบบไดนามิก):"
Matt

โอเคโอเค ... คุณพูดถูก ถ้าอย่างนั้นขอบอกว่านั่นเป็นวิธีที่ง่ายที่สุดในการทำงาน ...
นิโคลัส Manzini

9

ได้รับข้อผิดพลาดเดียวกันโซลูชัน @LeeIII ทำงานให้ฉัน (ขอบคุณ!) ฉันขอแนะนำให้ปรับเปลี่ยนเล็กน้อย:

  • ใช้หมวดหมู่ -c วัตถุประสงค์เพื่อเก็บวิธีการใหม่ (ดังนั้นเราจะไม่สูญเสียวิธีการของเราหากรายการถูกสร้างขึ้นอีกครั้ง)
  • ตรวจสอบว่าเรามีชุดที่ไม่แน่นอน

เนื้อหาของ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

จุดดีที่จะย้ายรหัสนี้เป็นหมวดหมู่ แต่เรายังคงต้องยอมรับการเพิ่ม / ลบจริงด้วยความประสงค์ / setPrimitiveValue / didChange เช่นใน @Dmitry Makarenko คำตอบ
Vladimir Shutyuk

8

หากคุณใช้ mogenerator คุณควรเลือกใช้แทน

[parentObject add<Child>sObject:childObject];

ใช้เพียง:

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

เนื่องจาก mogenerator ดูแลรหัสพิเศษที่คุณจะต้องเขียนและอนุญาตให้เข้าถึงวัตถุชุดพื้นฐาน
Καrτhικ

ดูเหมือนว่าจะมีการแก้ไขแล้วซึ่งหมายความว่า mogenerator จะสร้างเนื้อหาที่ถูกแก้ไข ... github.com/dmakarenko/mogenerator/commit/
combinatorial

1
ฉันใช้mogeneratorแต่ฉันยังมีข้อบกพร่อง
Colas

7

ส่วนตัวฉันเพิ่งเปลี่ยนการเรียกไปยัง CoreData ที่สร้างวิธีด้วยการโทรโดยตรงไปยังวิธีการตามที่ระบุไว้ในโซลูชันอื่นโดย @Stephan:

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

สิ่งนี้จะลบความต้องการหมวดหมู่ที่อาจขัดแย้งกับโซลูชันจาก Apple ไปยังรหัสที่สร้างขึ้นเมื่อมีการแก้ไขข้อบกพร่อง

นี่เป็นข้อดีอีกอย่างของวิธีการทำอย่างเป็นทางการ!


สิ่งนี้ทำให้เกิดข้อผิดพลาดต่อไปนี้: '[<CLASS 0x20886d10> valueForUndefinedKey:]: คลาสนี้ไม่ใช่ค่าคีย์ที่เข้ารหัสตามมาตรฐานสำหรับคีย์ย่อย'
jmstone617

ในขณะที่มันยังทำให้ฉันหงุดหงิดไม่สิ้นสุดว่านี่ไม่ได้อยู่ในรายการปัญหาที่รู้จักของ Apple (ฉันได้เปิดเรดาร์สำหรับท่าทางที่ไร้ประโยชน์อย่างเห็นได้ชัดว่ามันเป็น) วิธีแก้ปัญหานี้ทำงานได้อย่างไม่มีที่ติสำหรับฉัน
Scott Corscadden

หวังว่าฉันจะได้เห็นคำตอบนี้ก่อนหน้านี้; ฉันใช้คำตอบที่ได้รับการโหวตสูงสุดจนกระทั่งเมื่อไม่นานมานี้ฉันได้ขุดบางอย่างและในที่สุดก็นำสิ่งที่คุณมีอยู่ที่นี่มาใช้ได้ :)
Ja --ck

ทำไมถึงถูกaddObject:เรียกสองครั้ง
Jason Moore

5

ดูเหมือนว่าหากคุณเชื่อมโยงผู้ปกครองกับเด็กด้วยการตั้งค่าผู้ปกครองให้กับเด็กและไม่ใช่วิธีอื่นที่อยู่รอบตัวมันจะทำงานโดยไม่หยุดทำงาน

ดังนั้นถ้าคุณ:

[child setParent:parent]

แทน

[parent setChildObects:child]

มันควรจะทำงานได้อย่างน้อยมันก็ใช้งานได้กับ iOS 7 และไม่มีปัญหาใด ๆ กับความสัมพันธ์


1
ไม่ได้ทำอะไรดีมากเมื่อทั้งสองฝ่ายมีจำนวนมาก จากนั้นไม่มีความสัมพันธ์พ่อแม่ลูกที่ชัดเจน
fatuhoku

3

ฉันมีปัญหาเดียวกัน แต่เฉพาะเมื่อฉันลองทำสิ่งที่แตกต่างกับสิ่งที่ฉันทำ ฉันไม่เห็นรหัสของรายการย่อย แต่ฉันจะถือว่ามันมีลิงค์กลับไปยังรายการ ให้เรียกลิงค์นี้ว่า "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;

ผลก็คือมันใช้ประโยชน์จากรหัสของแอปเปิลและมันก็ง่ายและสะอาด นอกจากนี้ชุดจะถูกเพิ่มโดยอัตโนมัติและผู้สังเกตการณ์ทั้งหมดจะได้รับการปรับปรุง ไม่มีปัญหา.


นี่เป็นสิ่งที่ดีมาก มันแก้ปัญหาทั้งหมดและทำให้มันสั่งเช่นกัน ยังคงบ้าว่าข้อบกพร่องยังคงอยู่ ประโยชน์อีกประการของคำตอบนี้คือถ้าคุณสร้างโมเดลข้อมูลหลักของคุณใหม่คุณไม่จำเป็นต้องเขียนแก้ไขข้อบกพร่องของคุณอีกครั้ง ขอบคุณ!
Johan S

ดูคำตอบอื่นของฉัน ฉันติดตามข้อผิดพลาดในรายละเอียดเพิ่มเติม นี่ยังคงเป็นวิธีที่ง่ายที่สุด แต่วิธีอื่นดีที่สุดเพราะเปิดโอกาสให้มากขึ้น
โอเวนก็อดฟรีย์

ว้าว! ในที่สุด !!! ขอบคุณ! (ลองใช้รหัสอื่นของคุณ แต่มีข้อผิดพลาดบางอย่างเกี่ยวกับประเภทที่ไม่ถูกต้องนั้นถูกส่งไปที่ [self didChange: NSKeyValueChangeInsertion valuesAtIndexes: indexSet forKey: ChildrenKey];)
Leonard Pauli

3

ฉันเพิ่งทำผิดพลาดของปัญหานี้และแก้ไขโดยใช้การดำเนินการที่ง่ายกว่าคนอื่น ๆ ที่ระบุไว้ที่นี่ ฉันเพียงแค่ใช้วิธีการที่มีอยู่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

ปัญหานี้เกิดขึ้นกับฉันขณะย้ายข้อมูลโครงการจาก Objective-C เป็นSwift 2ด้วย XCode 77 โครงการนั้นใช้งานได้และด้วยเหตุผลที่ดี: ฉันใช้ MOGenerator ซึ่งมีวิธีการเปลี่ยนเพื่อแก้ไขข้อผิดพลาดนี้ แต่ไม่ใช่ทุกวิธีที่จำเป็นต้องเปลี่ยนใหม่

ดังนั้นนี่คือโซลูชันที่สมบูรณ์พร้อมคลาสตัวอย่างโดยใช้ accessors เริ่มต้นมากที่สุด

สมมติว่าเรามีรายการที่มีรายการสั่งซื้อ

ก่อนชนะอย่างรวดเร็วหากคุณมีความสัมพันธ์แบบหนึ่งต่อหลายคนวิธีที่ง่ายที่สุดคือทำ:

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

ฉันยอมรับว่าอาจมีข้อผิดพลาดที่นี่ ฉันได้ปรับใช้งานการเพิ่มวัตถุ> ตัวตั้งค่าเพื่อผนวกอย่างถูกต้องกับ 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 จะเป็นที่เก็บข้อมูลความสัมพันธ์กับผู้ใช้จำนวนมาก


เพื่อให้ CoreData ส่งคืนหรือรับวัตถุ NSOrderedSet จะต้องปฏิบัติตามเงื่อนไขหลายข้อตามที่คำถามเริ่มต้นนี้ปรากฏขึ้น ข้อผิดพลาดทั่วไปส่วนใหญ่ที่ฉันเห็นเมื่อมีคนแชร์รหัสของฉันเป็นนักพัฒนาซอฟต์แวร์ที่ไม่ได้ใช้ Lion เฟรมเวิร์ก NSOrderedSets ไม่สามารถใช้งานได้กับ snowleopard แต่ใช่ฉันไม่เคยเห็นความล้มเหลวนี้แม้ว่าฉันจะไม่แน่ใจว่านี่เป็นประสิทธิภาพที่ดีที่สุด ฉันเดาว่ามันต้องใช้ทั้งชุดและแทนที่มันแทนที่จะใส่บันทึกที่ต้องการ
InitJason

2

ฉันคิดว่าทุกคนกำลังพลาดปัญหาที่แท้จริง มันไม่ได้เป็นวิธีการในการเข้าถึง แต่ในความเป็นจริงที่NSOrderedSetไม่ได้เป็น subclass 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

ดูเหมือนว่าการแก้ไขคือการเปลี่ยนการใช้งานของตัวดำเนินการชุดเพื่อให้พวกเขาจัดการประเภทโปร่งใส ไม่มีเหตุผลว่าทำไม-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

ฉันเพิ่งพบปัญหาใน Swift (Xcode 6.1.1)

คำตอบนั้นไม่ได้เข้ารหัสสิ่งใดหรือเพิ่มเติมในคลาสย่อย NSManagedObject ของคุณ ฉันคิดว่ามันเป็นความผิดพลาดของคอมไพเลอร์ ข้อผิดพลาดที่แปลกมาก ..

หวังว่ามันจะช่วย ..


3
ดังนั้นหากฉันไม่สามารถใช้การแก้ไขอื่น ๆ ฉันควรทำอย่างไรเพื่อแก้ไขปัญหานี้
Ben Leggiero

2

ฉันแก้ไขปัญหานี้โดยตั้งค่า Inverse เป็น No Inverse ฉันไม่ทราบสาเหตุอาจเป็นเพราะ Apple Bugป้อนคำอธิบายรูปภาพที่นี่


1

ฉันมีสถานการณ์เดียวกันกับรายการที่เรียกว่า "สัญญาณ" แทน "รายการย่อย" วิธีการแก้ปัญหากับ 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

ฉันพบคำถามนี้โดย googling สำหรับข้อความแสดงข้อผิดพลาดและต้องการชี้ให้เห็นว่าฉันพบข้อผิดพลาดนี้ในวิธีที่แตกต่างกันเล็กน้อย (ไม่ได้ใช้ชุดคำสั่ง) นี่ไม่ใช่คำตอบของคำถามที่ได้รับ แต่ฉันโพสต์ไว้ที่นี่ในกรณีที่เป็นประโยชน์กับคนอื่น ๆ ที่สะดุดในคำถามนี้ขณะค้นหา

ฉันเพิ่มรุ่นรุ่นใหม่และเพิ่มความสัมพันธ์บางอย่างกับรุ่นปัจจุบันและกำหนดวิธีเพิ่ม * Object ในไฟล์ส่วนหัวด้วยตัวเอง เมื่อฉันพยายามโทรหาพวกเขาฉันได้รับข้อผิดพลาดด้านบน

หลังจากตรวจสอบแบบจำลองของฉันฉันรู้ว่าฉันลืมที่จะตรวจสอบช่องทำเครื่องหมาย

ดังนั้นหากคุณพบปัญหานี้และคุณไม่ได้ใช้ชุดสั่งซื้อให้ตรวจสอบรุ่นของคุณอีกครั้ง


1

ฉันพบการแก้ไขข้อผิดพลาดนี้ที่เหมาะกับฉัน ฉันแค่แทนที่สิ่งนี้:

[item addSubitemsObject:subItem];

ด้วยสิ่งนี้:

item.subitemsObject = subItem;

1

รุ่นที่ดีกว่าของคำตอบที่ถูกต้องใน SWIFT

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

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

0

ฉันพบว่าการใช้วิธีการโดย LeeIII ทำงาน แต่เมื่อทำโปรไฟล์พบว่าช้ามาก ใช้เวลา 15 วินาทีในการแยกวิเคราะห์ 1,000 รายการ การใส่ความคิดเห็นในรหัสเพื่อเพิ่มความสัมพันธ์เปลี่ยนเป็น 15 วินาทีเป็น 2 วินาที

วิธีแก้ปัญหาของฉัน (ซึ่งเป็นเร็วขึ้น แต่ที่น่าเกลียดมากขึ้น) เกี่ยวข้องกับการสร้างอาร์เรย์แน่นอนชั่วคราวแล้วคัดลอกเป็นชุดที่สั่งซื้อเมื่อทุกแยกที่จะทำ (นี่เป็นเพียงการชนะการแสดงหากคุณจะเพิ่มความสัมพันธ์มากมาย)

@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

โรเบิร์ต

ฉันเห็นด้วยกับคำตอบของคุณจะทำงานได้ แต่โปรดจำไว้ว่ามีวิธีการที่สร้างขึ้นโดยอัตโนมัติสำหรับการเพิ่มค่าทั้งชุดให้กับความสัมพันธ์แล้ว เอกสารประกอบของ 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];
}

คุณสามารถรวบรวมชุดความสัมพันธ์ของคุณนอกข้อมูลหลักได้อย่างง่ายดายแล้วเพิ่มพวกเขาทั้งหมดในครั้งเดียวโดยใช้วิธีนี้ มันอาจจะน่าเกลียดน้อยกว่าวิธีที่คุณแนะนำ;)


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.