문제

One view of my iOS application is a UISearchDisplay. I have designed it as a type-ahead search, so that whenever the user enters a new character the table is re-populated. I have done this by implementing the UISearchDisplayDelegate protocol method:

searchDisplayController:shouldReloadTableForSearchString:

In this method I take the string provided and append it to my query URL. I then create a new NSURLConnection and submit a new asynchronous request. I receive and append data via the delegate method:

connection:didReceiveData:

Once the connection has finished downloading the data, via the method:

connectionDidFinishLoading

I pass the data to an instance of NSXMLParser. The data that is receive is an XML file of all the contacts in my database which match the given string. Once the data has finished being parsed I reload the table.

My Problem: If the user types in text fast enough, there will be multiple connection and parsing tasks going on at the same time. This is an issue because I have one instance of NSMutableData which I append data to and parse. Hopefully you can see where I am going with this.

Does anyone have any suggestions for improving my implementation and/or solving this critical-section problem?

도움이 되었습니까?

해결책

NSXMLParser is not asynchronous. This one trips a lot of people up, since they assume that it is due to its use of delegate callback methods. However, actually the parse method doesn't return until all the parsing is finished.

So while you may have multiple connections going at once, you won't have multiple parsing operations happening unless you've multithreaded it yourself.

To solve the multiple connections problem, how about instead of having one single NSMutableData you have one per connection? There are a number of ways to do that: you might want to look at answers to the following questions for ideas.

다른 팁

There is a nice implementation described at Cancellable asynchronous searching with UISearchDisplayController

The gist of the solution is such:

  • Create a NSOperationQueue instance where you'll perform your search operation and save it into a property of your UISearchDisplayDelegate implementation, let's name it searchQueue.

  • Implement searchDisplayController:shouldReloadTableForSearchString: method. Note that this method returns a BOOL value, which signals the UISearchDisplayController instance to reload the table view. The method could be implemented like so:

    -(BOOL)searchDisplayController:(UISearchDisplayController *)controller 
    shouldReloadTableForSearchString:(NSString *)searchString {
        if ([searchString isEqualToString:@""] == NO) {
            [self.searchQueue cancelAllOperations];
            [self.searchQueue addOperationWithBlock:^{
    
              NSArray *results = // fetch the results from
              // somewhere (that can take a while to do)
    
              // Ensure you're assigning to a local variable here.
              // Do not assign to a member variable.  You will get
              // occasional thread race condition related crashes 
              // if you do.            
    
              [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                // Modify your instance variables here on the main
                // UI thread.
                [self.searchResults removeAllObjects]; 
                [self.searchResults addObjectsFromArray:results];
    
                // Reload your search results table data.
                [controller.searchResultsTableView reloadData];
              }];
            }];
    
            return NO;
    
        } else {
            [self.searchResults removeAllObjects];
            return YES;
        }
    }
    
  • Don't forget to cancel any pending operations when the user dismisses the search UI.

         - (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
             [self.searchQueue cancelAllOperations];
         }
    
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top