Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to implement work queue in iOS where only newest request is handled?
    primarykey
    data
    text
    <p>In my iOS program the following happens: As the user types, a request is fired off to a thread where a database lookup is initiated. When the DB lookup is done, a response is fired off on the main thread so the app can display the results.</p> <p>This works great, except that if the user types really fast, there may be several requests in-flight. Eventually the system will catch up, but it seems inefficient.</p> <p>Is there a neat way to implement it so that if a request is initiated, I can detect that a lookup is already in progress, and the request should instead be stored as "potentially newest that superceeds the one in-flight"?</p> <p>SAMPLE SOLUTION WITH COMMENTS ADDED BELOW</p> <p>Here's the body of a view controller for a small sample project that illustrates the properties of the solution. When typing you might get output like this:</p> <pre><code>2012-11-11 11:50:20.595 TestNsOperation[1168:c07] Queueing with 'd' 2012-11-11 11:50:20.899 TestNsOperation[1168:c07] Queueing with 'de' 2012-11-11 11:50:21.147 TestNsOperation[1168:c07] Queueing with 'det' 2012-11-11 11:50:21.371 TestNsOperation[1168:c07] Queueing with 'dett' 2012-11-11 11:50:21.599 TestNsOperation[1168:1b03] Skipped as out of date with 'd' 2012-11-11 11:50:22.605 TestNsOperation[1168:c07] Up to date with 'dett' </code></pre> <p>In this case, the first enqueued operation is skipped because it determines that it has become outdated while performing the lengthy part of its work. The two following enqueued operations ('de' and 'det') are cancelled before they are even allowed to execute. The final final operation is the only one to actually finish all its work.</p> <p>If you comment out the [self.lookupQueue cancelAllOperations] line, you get this behavior instead:</p> <pre><code>2012-11-11 11:55:56.454 TestNsOperation[1221:c07] Queueing with 'd' 2012-11-11 11:55:56.517 TestNsOperation[1221:c07] Queueing with 'de' 2012-11-11 11:55:56.668 TestNsOperation[1221:c07] Queueing with 'det' 2012-11-11 11:55:56.818 TestNsOperation[1221:c07] Queueing with 'dett' 2012-11-11 11:55:56.868 TestNsOperation[1221:c07] Queueing with 'dette' 2012-11-11 11:55:57.458 TestNsOperation[1221:1c03] Skipped as out of date with 'd' 2012-11-11 11:55:58.461 TestNsOperation[1221:4303] Skipped as out of date with 'de' 2012-11-11 11:55:59.464 TestNsOperation[1221:1c03] Skipped as out of date with 'det' 2012-11-11 11:56:00.467 TestNsOperation[1221:4303] Skipped as out of date with 'dett' 2012-11-11 11:56:01.470 TestNsOperation[1221:c07] Up to date with 'dette' </code></pre> <p>In this case, all the enqueued operation will perform the length part of their work, even though a newer operation has been enqueued after it before it has even been scheduled for execution.</p> <pre><code>@interface SGPTViewController () @property (nonatomic, strong) NSString* oldText; @property (strong) NSOperationQueue *lookupQueue; @end @implementation SGPTViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.oldText = self.source.text; self.lookupQueue = [[NSOperationQueue alloc] init]; self.lookupQueue.maxConcurrentOperationCount = 1; } - (void)textViewDidChange:(UITextView *)textView { // avoid having a strong reference to self in the operation queue SGPTViewController * __weak blockSelf = self; // you can cancel existing operations here if you want [self.lookupQueue cancelAllOperations]; NSString *outsideTextAsItWasWhenStarted = [NSString stringWithString:self.source.text]; NSLog(@"Queueing with '%@'", outsideTextAsItWasWhenStarted); [self.lookupQueue addOperationWithBlock:^{ // do stuff NSString *textAsItWasWhenStarted = [NSString stringWithString:outsideTextAsItWasWhenStarted]; [NSThread sleepForTimeInterval:1.0]; if (blockSelf.lookupQueue.operationCount == 1) { // do more stuff if there is only one operation on the queue, // i.e. this one. Operations are removed when they are completed or cancelled. // I should be canceled or up to date at this stage dispatch_sync(dispatch_get_main_queue(), ^{ if (![textAsItWasWhenStarted isEqualToString:self.source.text]) { NSLog(@"NOT up to date with '%@'", textAsItWasWhenStarted); } else { NSLog(@"Up to date with '%@'", textAsItWasWhenStarted); } }); } else { NSLog(@"Skipped as out of date with '%@'", textAsItWasWhenStarted); } }]; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload