iOS Core Data ко многим разрывается при удалении объекта с использованием созданных методов доступа - PullRequest
1 голос
/ 16 августа 2011

У меня есть приложение для iOS 4 +, которое сейчас модифицируется для использования Core Data. У меня есть сущность «Статья», которая имеет отношение ко многим другим сущностям «MediaResource», и я сгенерировал подклассы NSManagedObject для каждого. Отношение называется «мультимедиа» и устанавливается как необязательное и для каскадного удаления связанных объектов MediaResource. Назад к статье есть обратный-один.

Сгенерированный код включает свойство типа NSSet * media в класс Article, а также следующие методы:

- (void)addMediaObject:(MediaResource *)value {    
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
    [self willChangeValueForKey:@"media" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
    [[self primitiveValueForKey:@"media"] addObject:value];
    [self didChangeValueForKey:@"media" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
    [changedObjects release];
}

- (void)removeMediaObject:(MediaResource *)value {
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
    [self willChangeValueForKey:@"media" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
    [[self primitiveValueForKey:@"media"] removeObject:value];
    [self didChangeValueForKey:@"media" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
    [changedObjects release];
}

- (void)addMedia:(NSSet *)value {    
    [self willChangeValueForKey:@"media" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];
    [[self primitiveValueForKey:@"media"] unionSet:value];
    [self didChangeValueForKey:@"media" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];
}

- (void)removeMedia:(NSSet *)value {
    [self willChangeValueForKey:@"media" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];
    [[self primitiveValueForKey:@"media"] minusSet:value];
    [self didChangeValueForKey:@"media" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];
}

Здесь нигде нет NSMutableSets, но я предполагаю, что автоматически сгенерированный код знает, что он делает.

Я могу добавить статью, затем добавить к ней объект MediaResource и сделать это следующим образом:

            [newArticle addMediaObject:newMediaObject];

Я собираю из документов, что это правильный путь. Тем не менее, я также вижу ссылку на использование mutableSetValueForKey:, но здесь это не применимо.

В основном, происходит то, что во время данного прогона я могу добавить статью, затем удалить ее, и она работает нормально. Однако, если я затем добавлю его, выйду из приложения, затем перезапущу его, а затем удалю, я получу исключение, когда он говорит NSSet удалить объект, что, конечно, он не может сделать. Поскольку я на самом деле не писал эти методы, я запутался. Есть идеи? Вот соответствующая трассировка стека:

2011-08-16 11:12:32.141 MyApp[41825:207] -[__NSSet0 removeObject:]: unrecognized selector sent to instance 0x8041f60
2011-08-16 11:12:32.144 MyApp[41825:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSet0 removeObject:]: unrecognized selector sent to instance 0x8041f60'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x01a5b5a9 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x01baf313 objc_exception_throw + 44
    2   CoreFoundation                      0x01a5d0bb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
    3   CoreFoundation                      0x019cc966 ___forwarding___ + 966
    4   CoreFoundation                      0x019cc522 _CF_forwarding_prep_0 + 50
    5   CTKennedy                           0x000b292c -[Article removeMediaObject:] + 220
    6   CoreData                            0x0054a1f2 -[NSManagedObject(_NSInternalMethods) _excludeObject:fromPropertyWithKey:andIndex:] + 98
    7   CoreData                            0x0053f7d1 -[NSManagedObject(_NSInternalMethods) _maintainInverseRelationship:forProperty:oldDestination:newDestination:] + 449
    8   CoreData                            0x00593b55 -[NSManagedObject(_NSInternalMethods) _propagateDelete:] + 1541
    9   CoreData                            0x0054a02a -[NSManagedObject(_NSInternalMethods) _propagateDelete] + 42
    10  CoreData                            0x00549e53 -[NSManagedObjectContext(_NSInternalChangeProcessing) _propagateDeletesUsingTable:] + 515
    11  CoreData                            0x00549c12 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processDeletedObjects:] + 146
    12  CoreData                            0x0053cba8 -[NSManagedObjectContext(_NSInternalChangeProcessing) _propagatePendingDeletesAtEndOfEvent:] + 104
    13  CoreData                            0x00508982 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 754
    14  CoreData                            0x00542715 -[NSManagedObjectContext save:] + 149

1 Ответ

3 голосов
/ 17 августа 2011

Ваша проблема не связана с автоматически сгенерированным кодом. Вы не видите изменяемый набор, потому что Core Data фактически использует кластер классов для NSSet и возвращает другой класс _NSFaultingMutableSet при обращении к связи со многими. NSSet, скорее всего, используется в заголовке, чтобы другие классы не пытались установить отношения без использования определенных методов.

У меня есть сгенерированная установка класса Alpha с отношением ко многим betas к классу Beta. Если я поставлю точку останова в первой строке этого метода:

-(void)addBetasObject:(NSManagedObject *)value {    
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
    [self willChangeValueForKey:@"betas" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
    [[self primitiveValueForKey:@"betas"] addObject:value];
    [self didChangeValueForKey:@"betas" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
    [changedObjects release];
}

... Затем я могу сделать это в приглашении отладчика:

(gdb) po [self primitiveValueForKey:@"betas"]
Relationship objects for {(
)} on 0x4d45e20
(gdb) po [[self primitiveValueForKey:@"betas"] class]
_NSFaultingMutableSet

Таким образом, несмотря на заголовок, свойство является изменяемым, хотя и настраиваемым.

Аналогично, методом сопоставления:

- (void)removeBetasObject:(NSManagedObject *)value {
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
    [self willChangeValueForKey:@"betas" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
    [[self primitiveValueForKey:@"betas"] removeObject:value];
    [self didChangeValueForKey:@"betas" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
    [changedObjects release];
}

... после сохранения отладчик выдает:

(gdb) po [self primitiveValueForKey:@"betas"]
Relationship objects for {(
    <Beta: 0x4d4be40> (entity: Beta; id: 0x4d52510 <x-coredata://64E86DEC-53DA-4197-B1F3-6C0007576100/Beta/p1> ; data: {
    alphas =     (
        "0x4d52140 <x-coredata://64E86DEC-53DA-4197-B1F3-6C0007576100/Alpha/p1>"
    );
    num = 0;
})
)} on 0x4d45e20
(gdb) po [[self primitiveValueForKey:@"betas"] class]
_NSFaultingMutableSet

Это скрытое изменение класса происходит из-за директивы процессора @dynamic для betas, т. Е. @dynamic betas;, и если эта строка будет удалена, то атрибуты будут определены просто так, как они находятся в заголовке.

Проверьте файл Article.m на наличие @dynamic media;. Если он отсутствует или является @synthesize media;, является источником вашей проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...