Базовые данные: -deleteObject: Сбои. Являются ли правила удаления причиной? - PullRequest
3 голосов
/ 24 февраля 2010

У меня есть следующая модель, как вы можете видеть на картинке.

альтернативный текст http://img521.imageshack.us/img521/9741/schermata20100224a12251.png

Мое приложение требует обновления каждого экземпляра B, поэтому при каждом viewWillAppear мне нужно удалить все B в модели. После удаления B правило каскадного удаления в отношении к C удалит все C и затем каскадно ко всем D. A & E - это константы.

У меня есть DeleteRule для каждого объекта следующим образом:

A: b - Cascade
B: c - Cascade, a - Nullify
C: b - Nullify, d - Cascade
D: c - Nullify, e - Nullify
E: d - Cascade

или

A -(cascade)->> B -(cascade)-> C -(cascade)->> D -(nullify)-> E
A <-(nullify)- B <-(nullify)- C <-(nullify)- D <-(nullify) E

У меня проблема с каскадным удалением на всех B, C, D. Мой объект fetchRequest возвращает каждый экземпляр B в A, а затем я вызываю -deleteObject: для каждого B из управляемогоObjectContext. Но существует EXC_BAD_ACCESS при вызове [managedObjectContext save: & error] .

Может кто-нибудь показать мне, что я делаю не так? У меня проблемы с DeleteRule на каждой сущности или проблема лежит в другом месте? Каковы оптимальные методы обработки каскадного удаления на трех объектах B, C, D?

Отредактировано:

Вот трассировка стека при возникновении ошибки:

  #0    0x01d843ae in ___forwarding___
  #1    0x01d606c2 in __forwarding_prep_0___
  #2    0x01c618b6 in -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:]
  #3    0x0003263a in _nsnote_callback
  #4    0x01d4f005 in _CFXNotificationPostNotification
  #5    0x0002fef0 in -[NSNotificationCenter postNotificationName:object:userInfo:]
  #6    0x01bc217d in -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:]
  #7    0x01c21763 in -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:]
  #8    0x01ba65ea in -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:]
  #9    0x01bdc728 in -[NSManagedObjectContext save:]

Вот журнал в консоли, когда я пытался установить NSZombieEnabled & MallocStackLogging на YES:

  2010-02-24 15:41:39.803 Foo[2591:207] deleting object: FUM5
  2010-02-24 15:41:40.515 Foo[2591:207] *** -[viewController controllerWillChangeContent:]: message sent to deallocated instance 0x7e54510

Редактировать 2: КОД ИСТОЧНИКА ДОБАВЛЕН

Я попытался воссоздать ситуацию, создав новый проект с точной схемой на изображении. Вы можете скачать его отсюда . Также есть текст README. Надеюсь, что я дал достаточно информации.

Ответы [ 2 ]

3 голосов
/ 24 февраля 2010

Я полагаю, что проблема может заключаться в необходимом отношении между C и D. Если график настроен так, что:

  1. Для каждого C требуется хотя бы один D.
  2. Многие экземпляры C указывают на один и тот же D.

Тогда в некоторый момент C, вероятно, обнаружит, что его обязательные отношения были аннулированы. Если он все равно попытается получить доступ к D, это вызовет EXC_BAD_ACCESS. (Если каждому E требуется один D, у вас может возникнуть та же проблема)

Для отладки я предлагаю,

  • Установите отношение C -> D как необязательное и посмотрите, исчезнет ли ошибка.
  • Измените каскады на нули по одному, начиная с C -> D, и посмотрите, исчезнет ли ошибка.
  • Если у вас есть классы, убедитесь, что экземпляры не имеют общего объекта вне графа сущностей. Например, классы C и D имеют ссылку на одно и то же изображение, но это изображение не является частью объекта. Если внешние ссылки не сохранены должным образом, это также может вызвать аналогичный сбой.
  • Переместите сохранение в сразу после вызова, чтобы удалить каждый B. Зарегистрируйте каждый B и его C перед удалением. Таким образом, вы сможете точно увидеть, где произошла ошибка сохранения, и в каком состоянии находится график, когда это происходит.

Edit01:

Хорошо, я посмотрел ваш код и обнаружил проблему.

Проблема в том, что у вас есть отношение "b" набора A к требуемому. Когда вы удаляете B, он выдает эту ошибку:

2010-02-24 16:14:02.064 CoreDataTestDeleteRule[20887:207] Unresolved error Error Domain=NSCocoaErrorDomain Code=1580 UserInfo=0x3d0b450 "Operation could not be completed. (Cocoa error 1580.)"
2010-02-24 16:14:06.340 CoreDataTestDeleteRule[20887:207] Unresolved error Error Domain=NSCocoaErrorDomain Code=1580 UserInfo=0x3d19980 "Operation could not be completed. (Cocoa error 1580.)", {
    NSLocalizedDescription = "Operation could not be completed. (Cocoa error 1580.)";
    NSValidationErrorKey = b;
    NSValidationErrorObject = <A: 0x3b2faf0> (entity: A; id: 0x3d05330 <x-coredata://6870AF7C-E28F-4B4E-80AB-09C648651179/A/p1> ; data: {
    b =     (
    );
    name = a;

( Кстати, текстовые ошибки для числовых кодов ошибок Базовых данных можно найти в CoreDataErrors.h. )

Это имеет смысл, потому что вы требуете от A иметь b, а затем удаляете все b. Простое установление отношения A - >> B для необязательного предотвращает ошибку и позволяет коду нормально работать.

У вашего кода также есть другие проблемы. Некоторые из автоматически сгенерированных классов оказались не правильно. Например, интерфейс для B.h выглядит так:

#import <CoreData/CoreData.h>

@class A;

@interface B :  NSManagedObject  
{
}

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) A * a;
@property (nonatomic, retain) NSManagedObject * c;

@end

Когда это должно выглядеть так:

#import <CoreData/CoreData.h>

@class A;
@class C;

@interface B :  NSManagedObject  
{
}

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) A * a;
@property (nonatomic, retain) C * c;

@end

Я не уверен, почему они не сработали правильно.

Я бы также не советовал использовать короткие имена переменных и классов. Objective-c имеет глобальное пространство имен, и использование однобуквенных символов является приглашением для конфликта имен. Вы никогда не знаете, кто еще спешил. Я рекомендую использовать старый фонетический алфавит в стиле Второй мировой войны (современный также рискует столкновениями) и тестовые классы имен: Адам, Бейкер, Чарли, Дэвид, Эдди и т. Д.

Похоже, мы оба сфокусировались на отношениях B <-> C <- >> D и пренебрегли, чтобы смотреть дальше. Это отладочная версия программистом «фиксации цели» военными. Вы застряли на одном понятии проблемы и не можете встряхнуться.

2 голосов
/ 24 февраля 2010

Что вы делаете в ваших NSFetchedResultsControllerDelegate методах? Исходя из трассировки стека, похоже, что вы делаете что-то смешное в одном из них. В идеале эти делегаты должны обновлять только UITableView, к которому они прикреплены. Если вы что-то делаете с экземплярами NSManagedObject или NSManagedObjectContext в одном из этих методов, это может привести к сбою, подобному следующему.

Я бы предложил установить точку останова на objc_exception_throw, и это может дать вам больше информации о точной точке возникновения проблемы.

Обновление

Я посмотрел код, и вы пытаетесь удалить B, в то время как A имеет обязательное свойство для этого B. Это вызывает ошибку проверки. Вы не можете удалить объект, который другой объект имеет в качестве обязательного отношения.

...