Objective-C - Canceling a thread?

2019-04-16 01:07发布

问题:

I have a search function in my app where the user types in the textField, and as the text changes I am searching the local database and populating data in a table.

The search might take anywhere between 1 to 10 seconds depending on the text entered, so I decided to use a thread. Every time the text changes I want to cancel the thread (If running already), and start it again with the new keyword. The problem is that according to the documentation calling cancel doesn't guaranty that the thread will be killed. So what is the solution here?

Is there any way to kill a thread?

- (void)populateData
{
   if (self.searchThread.isExecuting)
   {
       [self.searchThread cancel];
   }

   [self.searchThread start];
}

- (void)populateDataInBackground
{
   @autoreleasepool
   {
      // get data from db
      // populate table on main thread
   }
}

回答1:

You don't want the thread to die necessarily, as it will be reused later (making threads is expensive). What you should do is break your work into as many pieces as you can, and in between each piece check to see if your thread's isCancelled property is YES. If so, return without the update.

[NSThread currentThread] should return your thread while you are inside populateDataInBackground



回答2:

I ended up modifying my dataStorage to return 10 items at a time, just for testing. I might use another number later. This way I can exit the thread in my while loop.

Another advantage is that this way I can populate the table as I go through the items, instead of waiting for all data to be retrieved.

@interface ViewController

@property (nonatomic, strong) NSthread *searchThread;

@end

@implementation ViewController
@synthesize searchThread = _searchThread;

- (void)populateData
{
   [self.searchThread cancel];

   self.searchThread = [[NSThread alloc] initWithTarget:self selector:@selector(populateDataInBackground) object:nil];
   [self.searchThread start];
}

- (void)populateDataInBackground
{
   @autoreleasepool
   {
      [self.array removeAllObjects];

      // I added paging functionality to my sql, so I get let's say 10 records at a time
      while (/*has data*/)
      {
          NSArray *arrayOf10 = [self.dataStorage getdatafromIndex:startingIndex withCount:10];

          if ([[NSThread currentThread] isCancelled])
               [NSThread exit];

          [self.array addObjects:arrayOf10];
          [self.tableView performSelectorOnMainThread:@Selector(reloadData) withObject:nil waitUntilDone:NO];
      }
   }
}

@end


回答3:

One of a few possible solutions would include this:

Set some "BOOL" semaphore / property from your main thread (e.g. "searchNow") and read it periodically while you're going through your "populateData" background thread / task.

If the state changes to "NO" (assuming "searchNow" == YES implies that the task should continue), then exit your background thread.