2012-03-17 4 views
0

Я мог бы использовать некоторую помощь в отладке ошибки EXC_BAD_ACCESS, принятой в команде [context deleteObject:loan];. Ошибка получена в следующем делетете:Плохой доступ к данным ядра deleteObject

- (void)didCancelNewLoan:(Loan *)loan { 
    // save the context 
    NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext]; 

    [context deleteObject:loan]; // *** EXC_BAD_ACCESS here *** 

// This method is called from a the following method in a second class: 

- (IBAction)cancel:(id)sender { 
    [delegate didCancelNewLoan:self.loan]; 
} 

// The loan ivar is created by the original class 
// in the below prepare for Segue method: 

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 

    if ([segue.identifier isEqualToString:@"NewLoan"]) { 
     UINavigationController *navController = (UINavigationController *)[segue destinationViewController]; 
     LoanViewController *loanView = (LoanViewController *)[[navController viewControllers] lastObject]; 
     loanView.managedObjectContext = self.managedObjectContext; 
     loanView.delegate = self; 

     loanView.loan = [self createNewLoan]; 
     loanView.newLoan = YES; 
    } 


// Finally, the loan is created in the above 
// method's [self createNewLoan] command: 

- (NSManagedObject *)createNewLoan { 
    //create a new instance of the entity managed by the fetched results controller 
    NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext]; 
    NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity]; 
    NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context]; 
    [newManagedObject setValue:[NSDate date] forKey:@"timeStamp"]; 

    CFUUIDRef uuid = CFUUIDCreate(NULL); 
    CFStringRef uuidstring = CFUUIDCreateString(NULL, uuid); 
    //NSString *identifierValue = (__bridge_transfer NSString *)uuidstring; 
    [newManagedObject setValue:(__bridge_transfer NSString *)uuidstring forKey:@"identifier"]; 
    CFRelease(uuid); 
    CFRelease(uuidstring); 

    NSError *error; 
    [self.fetchedResultsController performFetch:&error]; 
    NSLog(@"%i items in database", [[self.fetchedResultsController fetchedObjects] count]); 

    return newManagedObject; 
} 

Оцените свой взгляд на вышеуказанные методы.

ответ

1

Глядя на ваш код выше, нет ничего, что выделяется как делается неправильно.

Мне интересно, имеете ли вы дело с двумя различными контекстами управляемых объектов, не осознавая этого? Вам нужно будет установить некоторые точки останова, где вы создаете объект Loan, и посмотрите, может ли это быть так.

Также почему вы должны получить ссылку на контекст через fetchedResultsController, если у вас уже есть объявленное свойство для него в self.managedObjectContext?

Другое дело, почему вам нужно позвонить fetchedResultsController в performFetch: еще раз, когда вы создаете новый объект Loan? Представлены ли ваши данные в виде таблиц и были ли реализованы методы делегатов NSFetchedResultsController?

Этот вызов кажется ненужным, и это может вызвать проблемы с кешем, созданным приемом. См. Раздел «Изменение запроса на выборку» по этой ссылке http://developer.apple.com/library/ios/documentation/CoreData/Reference/NSFetchedResultsController_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40008227-CH1-SW24

Наконец, попробуйте выполнить операцию удаления непосредственно в контроллере представления, который получил действие, а не передал его делегату (просто чтобы исключить возможность того, что что-то было dealloc ' d без вашего ведома).

Вот что я хотел бы сделать:

- (IBAction)cancel:(id)sender 
{ 
    NSError *error; 
    NSManagedObjectContext *context = [self.loan managedObjectContext]; 
    [context deleteObject:self.loan]; 
    if (![context save:&error]) 
     NSLog (@"Error saving context: %@", error); 
} 
+0

Благодарим за отзыв. Я попробовал несколько ваших предложений. При запуске кода выше в контроллере представления, который получил действие, я получаю ту же ошибку. Я включил зомби и получил больше информации об ошибках: «[Сохранение CFString]: сообщение отправлено на освобожденный экземпляр ...» И, да, ваши данные верны, данные отображаются в представлении таблицы, и я реализовал методы делегирования NSFetchedResultsController при приеме просмотрите контроллер. – Jack

+0

Можете ли вы попробовать '__bridge' ваш CFString, а не' __bridge__transfer'? Похоже, что ваш объект CFString будет выпущен слишком рано. – Rog

+0

Или оставьте это как есть и НЕ отпустите 'uuidstring', поскольку ARC делает это для вас в соответствии с моим пониманием документации. – Rog

2

Угадай # 1: вы получаете доступ к освобожденному объекту. Отладить: включить зомби и посмотреть, что произойдет.

Обновление: вот как вы включаете зомби в Xcode 5:

продукта> Схема> Редактировать Схема, вкладка выберите Diagnostics, установите флажок "Включить зомби объекты"

scheme diagnostics settings

для старше Xcode

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

(and and check these arguments in your build scheme)


Guess # 2: у вас есть многопоточные приложения, и вы обращаетесь к контексту управляемых объектов из различных потоков, которое нет нет.

Вы можете добавить Assert до вашего удаления:

assert([ NSThread isMainThread ]) ; 
0

Я получил Плохой доступ, потому что перераспределена UIViewController был делегатом из NSFetchedResultsController он имел.

NSFetchedResultsController был освобождаться - но когда настройки делегата, он отмечает NSManagedObjectContext изменения, поэтому, когда NSManagedObjectContext был спасен - плохой доступ будет происходить при попытке уведомить NSFetchedResultsController об изменении.

Решение состоит в том, чтобы удалить делегат NSFetchedResultsController после освобождения.

- (void)dealloc { 
    fetchedResultsController.delegate = nil; 
} 
Смежные вопросы