s1m0n
s1m0n

Reputation: 7685

UITableView reloadData asynchronous

I'm making a search function for my application that I want to highlight the search string in the cell.
To do this, I save the search string to a global variable activeSearchString that can be accessed by tableView:cellForRowAtIndexPath.
tableView:cellForRowAtIndexPath then highlights the content of activeSearchString in the cell it will return. However, it isn't working. If you check the log, it seems like reloadData is performed asynchronous (so after activeSearchString has been deallocated).
Because of this, my app also crashes.. Any solution to perform reloadDatasynchronous or another approach? Thanks!

Code:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(){
    // Get the products asynchronous    
    NSString* searchString = [NSString stringWithString:@"A search string"];
    NSArray* searchResults = [[ProductServer sharedServer] productsForSearchString:searchString];
    dispatch_sync(dispatch_get_main_queue(), ^(){
        DLog(@"Begin");
        activeSearchString = [searchString retain];
        products = [searchResults retain];
        [ibTableView reloadData];
        [activeSearchString release];
        DLog(@"End");
    });
});

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        DLog();
        ProductTableViewCell* tableViewCell = [tableView dequeueReusableCellWithIdentifier:@"productCell" forIndexPath:indexPath];
        Product* product = [products objectAtIndex:[indexPath row]];

        NSDictionary* highlightAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIColor colorWithRed:49.f/255.f green:110.f/255.f blue:184.f/255.f alpha:1.f], NSBackgroundColorAttributeName, nil];
        NSMutableAttributedString* mutableAttributedTitle = [[[NSMutableAttributedString alloc] initWithString:[product title]] autorelease];
        [mutableAttributedTitle setAttributes:highlightAttributes range:[[mutableAttributedTitle string] rangeOfString:activeSearchString options:NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch]];
        [(UILabel*)[tableViewCell titleLabel] setAttributedText:mutableAttributedTitle];

        return tableViewCell;
}

Log:

2012-11-13 14:56:00.783 ****[5810:c07] __58-[TVCurrentlyViewController searchBarSearchButtonClicked:]_block_invoke_2 [Line 190] Begin
2012-11-13 14:56:00.783 ****[5810:c07] __58-[TVCurrentlyViewController searchBarSearchButtonClicked:]_block_invoke_2 [Line 197] End
2012-11-13 14:56:00.783 ****[5810:c07] -[TVCurrentlyViewController tableView:cellForRowAtIndexPath:] [Line 117] 
2012-11-13 14:56:00.786 ****[5810:c07] -[TVCurrentlyViewController tableView:cellForRowAtIndexPath:] [Line 117] 
2012-11-13 14:56:00.787 ****[5810:c07] -[TVCurrentlyViewController tableView:cellForRowAtIndexPath:] [Line 117] 
2012-11-13 14:56:00.789 ****[5810:c07] -[TVCurrentlyViewController tableView:cellForRowAtIndexPath:] [Line 117] 
2012-11-13 14:56:00.790 ****[5810:c07] *** -[CFString length]: message sent to deallocated instance 0x75d6d00

Upvotes: 1

Views: 2496

Answers (1)

Jack Lawrence
Jack Lawrence

Reputation: 10782

You shouldn't be releasing a global there. Use a synthesized property with retain semantics and release in the view controller's dealloc method.

Edit:

Use dispatch_async() instead of dispatch_sync() in your call back to the main thread. dispatch_sync() will block the global background queue while the main thread finishes updating the tableview.

Upvotes: 4

Related Questions