2015-05-07 16 views
6

Mam metodę -[tableView reloadData] w mojej aplikacji i aby wykonać wykonanie szybciej, nazwałem ją w GCD w poniższej metodzie.Zatrzymaj wykonywanie GCD, gdy pojawi się ViewController

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

    [tableView reloadData]; 
});  

Ale kiedy pop mój viewController, awarii aplikacji z tym komunikatem [SecondViewController numberOfSectionsInTableView:]: message sent to deallocated instance 0x7fe376206e10. Zakładam, że [reloadData] jest nadal wykonywany po wyjściu z tego ViewController. Jak mogę zatrzymać jego wykonanie? Czy powinienem zrobić to w NSOperation? Jeśli tak, jak mam to zrobić?

+0

Gdzie i kiedy nazywasz tę metodę GCD? – Leo

+0

wewnątrz mojego '- (void) tableView: (UITableView *) tableView willDisplayCell: (UITableViewCell *) komórka forRowAtIndexPath: (NSIndexPath *) indexPath' proszę nie pytać dlaczego, to długa historia –

+1

Tutaj jest cień kodu, ale gdy prosiliście nas, abyśmy nie pytali, nie zrobię tego. Ale, jeśli chcesz anulować coś, co dzieje się w 1,5 sekundy, prawdopodobnie lepiej jest użyć 'NSTimer' (który możesz łatwo anulować, wywołując' unieważnienie' na obiekcie timera) zamiast 'dispatch_after'. – Rob

Odpowiedz

2

Jest kilka problemów z kodem. Oto sekwencja zdarzeń prowadzących do katastrofy. 1) Blok przechwytuje tableView i utrzymuje go przy życiu.

2) Twój kontroler widoku jest następnie zwalniane przez pop,

3) Skrypt wykonywany bloku i tableView wywołuje przez to do źródła danych (kontroler widok), który jest teraz zwalniane.

Możesz rozwiązać ten problem, zatrzymując numer 1 lub 3 powyżej. Sugerowałbym # 1. (Zakładam tutaj ARC)

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

Jeśli to nie zadziała, coś innego prawdopodobnie utrzyma stół przy życiu. Należy zbadać, co dokładnie robi to, ale można również naprawić awarię poprzez zapobieganie nr 3 z widoku kontrolerów dealloc metody:

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

'- (void) dealloc' pracował. Czy powinienem się martwić o coś tutaj? –

+0

Zawsze najlepszym rozwiązaniem jest wyeliminowanie delegatów/źródeł danych w dealloc z tego powodu. – Lance

-1

Niestety, nie można zatrzymać wykonywanie GCD, ale jest inny sposoby napraw ten błąd. Ponieważ głównym pytaniem w tym wątku jest zatrzymanie wykonywania, opublikuję rozwiązanie w oparciu o to, o co prosisz, używając NSOperation.

1- Utwórz NSOperationQueue

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

2- Odśwież swoją tabelę z kolejki. (Będę używał bloki ok?)

[_myQueue addOperationWithBlock:^{ 

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

3- Teraz można anulować wykonanie przy użyciu

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

Aktualizacja:

Ojej, widziałem, że są opóźnienia przeładowanie stołowego call, ale NSOperation nie ma mechanizmu opóźnienia. Aby rozwiązać ten problem można symulować opóźnienia przy użyciu

[NSThread sleepForTimeInterval:1.5]; 

przed wywołaniem [tableView reloadData]; w addOperationWithBlock: lub kontynuować korzystanie GCD jak robisz teraz, i zmieniając odniesienie tableview do weak uniknąć bloku zachowując swój obiekt Tableview, jak to :

__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]; 
}); 

Mam nadzieję, że pomoże ...

+0

Dzięki temu awarie są nadal możliwe, ponieważ deallocation kontrolera widoku może się zdarzyć po uruchomieniu bloku, ale przed wywołaniem polecenia reloadData. Nie uwzględnia to również opóźnień, których chce. – Lance

+0

I dlatego powinieneś użyć '[_myQueue cancelAllOperations];'. – FormigaNinja

0

Jako opcję można słabo zachowują źródło danych i sprawdzić go:

__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]; 
    } 
}); 

Nadal jest bardzo mało prawdopodobne, awaria, jeśli trzymać źródło danych, ustawić nowe do widoku tabeli i usuń go ponownie, więc jest zwalniany.

Powiązane problemy