Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,558
6,058
So far, this is how my app works: the user types in a web address, and as they type, the app tries to scan pages for RSS feeds. To do this, quickly and without blocking the main thread, it creates a bunch of NSOperations running on their own threads, plus a Queue to manage them.

As each operation finishes scanning an RSS feed, it calls this method in my table view controller:

Code:
-(void)searchGotRSS:(NSDictionary*)dictionary {
    [self.tableView beginUpdates];
    [feeds addObject:dictionary];
    [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:[feeds count]-1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
    [self.tableView endUpdates];
    [self promptUpdate];
}

feeds is an NSMutableArray iVar.
promptUpdate just updates the search prompt. (By using the prompt, I don't need to bother with inserting a cell that tells the user what's going on.)

My number of rows method is this:
Code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [feeds count];
}

And I only have a single section, so the number of section method just returns 1 always.

My app works perfectly somewhere around 40% of the time, but I'd say 60% of the time it prints out something like this:
Code:
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-1914.84/UITableView.m:1037
2012-09-13 23:55:50.560 FeedReader[29052:8003] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0.  The number of rows contained in an existing section after the update (3) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

It seems to me that my method should work all the time, because it always starts with a call to the tableView to beginUpdates, which locks it from being edited by other threads, correct?, it follows it up with the data being edited and the new row being inserted, and then it ends with an endUpdates. I don't see how it's possible for me to end up with a different count in my datasource vs. in my view? (If you need more code than I've provided, I'll be happy to share.)
 
Last edited:

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,558
6,058
All UI updates must be done on the main thread. Is that how searchGotRSS: is being handled?

!!!

The RSSSearchOperation (which is on its own thread) simply uses this:

Code:
[self.delegate searchGotRSS:feed];

I think of objects as being on threads, but I'm suddenly thinking that I'm incorrect about that. The fact that the delegate is on the main thread... isn't actually a fact at all?

Sometimes the code works perfectly though... but I guess that just means that sometimes I get lucky?

Now I'm wondering whether I should modify the invocation of searchGotRSS (so it gets called on the main thread) or if I should modify the inside of the method, so that it switches itself to the main thread (if that makes sense? This is the first time I've ever tried writing code on my own that uses threads... in the past I've either avoided it or just been following someone else's tutorial.)
 

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
I think of objects as being on threads, but I'm suddenly thinking that I'm incorrect about that. The fact that the delegate is on the main thread... isn't actually a fact at all?
Nope, it's not. Objects are not on threads. Methods are run within threads.

Sometimes the code works perfectly though... but I guess that just means that sometimes I get lucky?
Sounds like it to me.

Now I'm wondering whether I should modify the invocation of searchGotRSS (so it gets called on the main thread) or if I should modify the inside of the method, so that it switches itself to the main thread (if that makes sense? This is the first time I've ever tried writing code on my own that uses threads... in the past I've either avoided it or just been following someone else's tutorial.)
I would modify searchGotRSS: so that only the part that does need to update the UI gets done within the main thread. I'm pretty sure you can find an easy way to do this, too.
 

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,558
6,058
I would modify searchGotRSS: so that only the part that does need to update the UI gets done within the main thread. I'm pretty sure you can find an easy way to do this, too.

Thanks for the help :)

My fixed code is this:

Code:
-(void)searchGotRSS:(NSDictionary*)dictionary {
    dispatch_async(dispatch_get_main_queue(),^ {
        [self.tableView beginUpdates];
        [feeds addObject:dictionary];
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:[feeds count]-1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
        [self.tableView endUpdates];
        [self promptUpdate];
    });
}

I figure just perform it all on the main thread... I don't think any of it is expensive and feeds needs to have the correct number of items in it. And other than adding the dictionary to my feeds array, the other methods are all UIUpdate related.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.