NSOperations or NSThread for bursts of smaller tasks that continuously cancel each other?

前端 未结 1 728
余生分开走
余生分开走 2020-12-30 18:36

I would like to see if I can make a \"search as you type\" implementation, against a web service, that is optimized enough for it to run on an iPhone.

The idea is th

相关标签:
1条回答
  • 2020-12-30 19:37

    Ok, I spend the last 8 hours reading up on every example out there. I came to realize that I would have to do some "Proof of Concept" code to see if there even would be a speed problem with building a new thread for "each" keystroke.

    It turns out that using NSOperation and NSOperationQueue is more than adequate, both in terms of speed and especially in terms of simplicity and abstraction.

    Is called after each keystroke:

    - (void) searchFieldChanged:(UITextField*) textField {
    
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
        NSString *searchString = textField.text;
    
        if ([searchString length] > 0) {
    
            [self performSelector:@selector(doSearch:) withObject:textField.text afterDelay:0.8f];
        }
    }
    

    This is mainly to stop the code form initiating a search for keystrokes that are less than 800 ms. apart. (I would have that a lot lower if it where not for the small touch keyboard).

    If it is allowed to time out, it is time to search.

    - (void) doSearch:(NSString*) searchString {
    
        [queue cancelAllOperations];
        ISSearchOperation *searchOperation = [[ISSearchOperation alloc] initWithSearchTerm:searchString];
        [queue addOperation:searchOperation];
        [searchOperation release];
    }
    

    Cancel all operations that is currently in the queue. This is called every time a new search is started, it makes sure that the search operation already in progress gets closed down in an orderly fashion, it also makes sure that only 1 thread is ever in a "not-cancelled" state.

    The implementation for the ISSearchOperation is really simple:

    @implementation ISSearchOperation
    
    - (void) dealloc {
    
        [searchTerm release];
        [JSONresult release];
        [parsedResult release];
        [super dealloc];
    }
    
    - (id) initWithSearchTerm:(NSString*) searchString {
    
        if (self = [super init]) {
    
            [self setSearchTerm:searchString];
        }
    
        return self;
    }
    
    - (void) main {
    
        if ([self isCancelled]) return;
        [self setJSONresult:/*do webservice call synchronously*/];
        if ([self isCancelled]) return; 
        [self setParsedResult:/*parse JSON result*/];
        if ([self isCancelled]) return;
    
        [self performSelectorOnMainThread:@selector(searchDataReady:) withObject:self.parsedResult waitUntilDone:YES];
    }
    
    @end
    

    There are two major steps, the downloading of the data from the web service and the parsing. After each I check to see if the search has been canceled by [NSOperationQueue cancelAllOperations] if it has, then we return and the object is nicely cleaned up in the dealloc method.

    I will probably have to build in some sort of time out for both the web service and the parsing, to prevent the queue from choking on a KIA object.

    But for now this is actually lightning fast, in my test I am searching an 16.000 entries dictionary and having Xcode NSLog it to the screen (slows things down nicely), each 800 ms. I issue a new search string via a timer and thereby canceling the old before it has finished its NSLog results to screen loop. NSOperationQueue handles this with no glitches and never more that a few ms. of two threads being executed. The UI is completely unaffected by the above tasks running in the background.

    0 讨论(0)
提交回复
热议问题