Stop GCD execution when ViewController opens

I have a method -[tableView reloadData] in my application and to speed up execution, I called it in the GCD in the following way.

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

But when I go out to my viewController, the application crashes with this message [SecondViewController numberOfSectionsInTableView:]: message sent to deallocated instance 0x7fe376206e10 . I assume that [reloadData] is still executing after exiting this ViewController. How can I stop its execution? Should I do this in NSOperation? If so, how will I do it?

+6
source share
3 answers

There are a couple of problems with your code. Here is the sequence of events leading to failure

1) The block captures the tableView and supports it.

2) Then your view controller is freed by the pop file,

3) The block is executed, and the tableView calls its data source (your view controller), which is now freed.

You can solve this problem by stopping either # 1 or # 3 above. I would suggest No. 1. (I guess here is ARC)

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

If this does not work, something else is likely to cause the tableView to stay alive. You should investigate what exactly this does, but you can also fix the failure by preventing # 3 from your controller of the dealloc view:

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

As an option, you can weakly save the data source and check it:

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

There is still a very unlikely failure if you hold the data source, install a new one in the table view and delete it again so that it is freed.

0
source

Unfortunately, you cannot stop the execution of the GCD, but there is another way to fix this error. Since the main issue in this thread is stopping execution, I will post a solution based on what you ask using NSOperation.

1- Create NSOperationQueue

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

2- Reload the table from your queue. (Will I use the blocks normally?)

 [_myQueue addOperationWithBlock:^{ //your really expensive function //and your table reload call [tableView reloadData]; }]; 

3 Now you can cancel execution using

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

Update:

I noticed that you are delaying a table reload call, but NSOperation does not have a delay mechanism. To solve this problem you can simulate a delay using

 [NSThread sleepForTimeInterval:1.5]; 

before calling [tableView reloadData]; inside addOperationWithBlock: or continue using GCD as you are doing right now and change the tableView link to weak to avoid blocking your tableView object, for example:

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

Hope this helps ...

-1
source

Source: https://habr.com/ru/post/986706/


All Articles