views:

705

answers:

2

I have a background thread listening to network, using a callback to process and store data. When it's ready (UI) controller gets a sync Notification, requests data, updates list and refreshes screen ...except screen doesn't update - until user scrolls the screen!

void aMessageArrivedCBack (const std::string text)
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSString *msg = [[[NSString alloc] initWithCString:(const char *)text.c_str() encoding:NSUTF8StringEncoding] autorelease];
    [[AMessageStore sharedInstance] aStoreMessage:msg];
    [pool drain];

    [[NSNotificationCenter  defaultCenter]
     postNotificationName:NOTIF_MessageReceived object:nil];
}

Here's the (UI) controller routine for Notification handling, the problem area:

- (void)aMessageWasReceived:(NSNotification*)aNotification
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [self.msgListView reloadData];
    [self.view setNeedsDisplay];
    [pool drain];
}

Question: how can I force screen update, when new message arrives? I have tried so many things I've lost count.. and just found out I'm trying same old things for fifth time. Still doesn't work.

What I already tried:

Note: "didn't work" below means that screen didn't update.

Data callback is running in non-UI thread, thus Notification is sent & received also in non-UI thread. Distributed notification are not available in iPhone OS, cannot use NSDistributedNotificationCenter.

[self.view setNeedsDisplay] and [self.msgListview setNeedsDisplay] don't work. Didn't really expect, not any more...

[self.msgListView performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO]; really should work, it didn't. I couldn't find object to send it to, I recall. At least "self" didn't work: unrecognized selector sent to instance at 0x14036f0. Terminating app due to uncaught exception 'NSInvalidArgumentException'. Self.msgListView works, but doesn't update screen.

[self.msgListView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop]; didn't work.

[self.msgListView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop]; didn't work

[self.msgListView visibleCells]; works ok, but what to do with it?

I am positive it's a small thing to fix, but I just can't find it.. Is there any ways to kick the (nice) UI thread or tableView for update? Could I call some _tableView didSelectRowAtIndexPath or anything? Can I do anything with appDelegate? How could I emulate "user scrolls the screen" event myself?

+2  A: 

When I do this in my apps I set a delegate for the background thread to send performSelectorOnMainThread:... to.

performSelectorOnMainThread is really the way to go here, most of those other things you list that you have tried do not work.

When you want to update a tableview you send it reloadData and it will in turn send setNeedsDisplay for the view to update. Have you tried that?

monowerker
Got it working, just like you said. Tried to do that several times, but "something" was always a bit wrong. The final trick which helped me to get it all together was this line of code to print Thread ID in debugger console NSLog(@"Thread %d", pthread_mach_thread_np(pthread_self()));
JOM
I am facing the same situation as urs. Can u plz say where do I have to use this line?
wolverine
A: 

It looks like -aMessageWasReceived: is issued in a non-UI thread, and it contains code that attempts to update the UI.

Try performing that method (or its UI-updating contents in a separate method) on the main thread, instead, to get the UI to update in a timely fashion.

Alex Reynolds
Knew these already, but didn't quite manage to make it clear in the question. Next time I'll try to write better description... Anyway, many thanx for support!
JOM