2015-05-07 4 views
6

У меня есть метод -[tableView reloadData] в моем приложении и сделать выполнение быстрее, я назвал его в GCD следующим способом.Остановить выполнение GCD при вызове ViewController

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ 

    [tableView reloadData]; 
});  

Но когда я сую свой ViewController, то приложение падает с этим сообщением [SecondViewController numberOfSectionsInTableView:]: message sent to deallocated instance 0x7fe376206e10. Я предполагаю, что [reloadData] все еще выполняется после выхода из этого ViewController. Как я могу остановить его выполнение? Должен ли я сделать это в NSOperation? Если да, то как мне это сделать?

+0

Где и когда вы называете этот метод GCD? – Leo

+0

in my '- (void) tableView: (UITableView *) tableView willDisplayCell: (UITableViewCell *) cell forRowAtIndexPath: (NSIndexPath *) indexPath', пожалуйста, не спрашивайте, почему, его длинный рассказ –

+1

Здесь есть намек на запах кода, но, как вы просили нас не спрашивать, я не буду. Но в нижней строке, если вы хотите отменить что-то, происходящее через 1,5 секунды, вероятно, лучше использовать 'NSTimer' (который вы можете легко отменить, вызвав' invalidate' на объект таймера), а не 'dispatch_after'. – Rob

ответ

2

Есть пара проблем с вашим кодом. Ниже приведена последовательность событий, ведущих к аварии

1) Блок захватывает таблицуView и сохраняет ее в силе.

2) Ваш контроллер представления затем освобождаться от поп-музыки,

3) блок выполняется и Tableview вызовы через к его источнику данных (ваш взгляд контроллер), который в настоящее время освобождаться.

Вы можете решить это, остановив либо # 1, либо # 3 выше. Я бы предложил №1. (Я принимаю здесь ARC)

__weak UITableView *weakTableView = tableView; 
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ 
    [weakTableView reloadData]; 
}); 

Если это не сработает, что-то еще, вероятно, сохранит таблицуView alive. Вы должны выяснить, что именно делаете это, но вы также можете исправить аварии, предотвращая # 3 из контроллеров зрения dealloc метода:

- (void)dealloc { 
    self.tableView.dataSource = nil; 
    self.tableView.delegate = nil; 
} 
+0

'- (void) dealloc' работал. Должен ли я беспокоиться о чем-то здесь? –

+0

Лучшей практикой является удаление делегатов/dataSources в dealloc по этой причине. – Lance

-1

К сожалению, вы не можешь остановить исполнение НОДА, но есть еще способы исправить эту ошибку. Поскольку основным вопросом в этом потоке является остановка выполнения, я отправлю решение на основе того, что вы просите, используя NSOperation.

1- Создать NSOperationQueue

NSOperationQueue *_myQueue; 
_myQueue = [NSOperationQueue new]; 
_myQueue.name = @"com.my.queue"; 

2- Обновить таблицу из очереди. (Я буду использовать блоки в порядке?)

[_myQueue addOperationWithBlock:^{ 

    //your really expensive function 
    //and your table reload call 
    [tableView reloadData]; 
}]; 

3- Теперь вы можете отменить выполнение с помощью

//maybe you will want to do this on viewDidDisappear 
[_myQueue cancelAllOperations]; 

Update:

Опа, я увидел, что вы задерживаете таблицы перезагрузки вызова, но NSOperation не имеет механизма задержки. Чтобы решить эту проблему можно смоделировать задержку с помощью

[NSThread sleepForTimeInterval:1.5]; 

перед вызовом [tableView reloadData]; внутри addOperationWithBlock: или продолжать использовать ГКД, как вы делаете сейчас, и изменение ссылки на Tableview, чтобы weak, чтобы избежать блока сохранения вашего объекта Tableview, как это :

__weak __typeof__(tableView) weakTable = tableView; 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ 

    //Now, if your table object was released at this point, the reloadData 
    //will be ignored 
    [weakTable reloadData]; 
}); 

Надеюсь, что это поможет ...

+0

При этом крах по-прежнему возможен, так как освобождение контроллера вида может произойти после того, как блок начнет выполнение, но до вызова reloadData. Это также не учитывает задержку, которую он хочет. – Lance

+0

И вот почему вы должны использовать '[_myQueue cancelAllOperations];'. – FormigaNinja

0

В качестве опции вы можете слабо сохранить источник данных и проверки на него:

__weak __typeof__(self) dataSource = self; // or whatever it is 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ 
    if (dataSource!=nil)  
    { 
    [weakTable reloadData]; 
    } 
}); 

Существует еще очень маловероятно аварии, если вы держите источник данных, установите новый в табличном и удалите это снова, чтобы он был освобожден.

Смежные вопросы