SetPrimitiveValue: отношения forKey: и to-many

Apple документация по -setPrimitiveValue:forKey: является неопределенной двумя способами, когда используется для управления отношениями "многие-многие".

Сначала они заявляют:

Если вы попытаетесь установить отношение "ко многим" к новому объекту NSMutableSet, он (в конце концов) потерпит неудачу.

В конце концов?! Что это значит? Повредет ли он позже во время -[NSManagedObjectContext save:]? Когда управляемый объект превращается в неисправность, а затем возвращается обратно? Когда? Могу ли я написать тестовый пример для последовательного воссоздания отказа по требованию?

Во-вторых, предоставляя пример кода для правильной обработки этого случая, они пишут:

сначала получите существующий набор, используя primitiveValueForKey: (убедитесь, что метод не возвращает nil)

Что делать, если/когда метод возвращает nil? assert() он и немедленно сбой, потому что это означает, что весь граф объекта поврежден и сохранение приведет к потере данных? NSAssert() на нем как предупреждение вызывающему, но нажмите (тихо ничего не делать)?

Прямо сейчас я просто прямо назначаю свой желаемый NS[Mutable]Set в этом случае, например:

- (void)setChildren:(NSSet*)value_ {
    NSMutableSet *mutableRelationshipSet = [[[self primitiveValueForKey:@"children"] mutableCopy] autorelease];
    if (mutableRelationshipSet) {
        [mutableRelationshipSet setSet:value_];
        [self setPrimitiveValue:mutableRelationshipSet forKey:@"children"];
    } else {
        [self setPrimitiveValue:value_ forKey:@"children"];
    }
}

Это неправильно?

Ответ 1

Просто измените возвращаемое значение -primitiveValueForKey: как изменяемый набор, полагая, что его возвращаемое значение будет правильным.

Обязательно используйте -willChangeValueForKey:withSetMutation:usingObjects: и -didChangeValueForKey:withSetMutation:usingObjects: вокруг своих манипуляций; вы не указали это в своем предыдущем коде.

- (void)setChildren:(NSSet *)value {
    [self willChangeValueForKey:@"children" withSetMutation:NSKeyValueSetSetMutation usingObjects:value];

    NSMutableSet *primitiveValue = [self primitiveValueForKey:@"children"];

    [primitiveValue setSet:value];

    [self didChangeValueForKey:@"children" withSetMutation:NSKeyValueSetSetMutation usingObjects:value];
}

Если вы можете нацелить Leopard, вам не нужно беспокоиться об этом; вы можете использовать встроенную поддержку свойств Core Data:

#import <CoreData/CoreData.h>

@interface Folder : NSManagedObject
@property (readwrite, retain) NSSet *children;
@end

@implementation Folder
@dynamic children;
@end

Core Data генерирует не только пару getter/setter для свойства children, но также и аксессуры с изменяемым набором, поэтому вы можете использовать -mutableSetValueForKey: на нем и управлять результатом с минимальными накладными расходами.