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

jctj

macrumors newbie
Original poster
Feb 24, 2010
18
0
I use a NSTableView and a NSLevelIndicator in my user interface.

When either of them change value, I correctly send the "reloadData" or "setNeedsDisplay" command. With the NSLevelIndicator, this is after setting the value with setIntValue: and with the NSTableView I have already updated the data that gets used in the numberOfRowsInTableView: and tableview:eek:bjectValueForTableColumn:row: methods. I know they work because they work just fine when the processing is done.

My problem is getting the GUI to respond to the updating commands sooner than it is. Is there a way to tell my method that is generating all the data to 'take a breather' and let the GUI do its update? I have searched through a lot of documentation, and I can't find anything that deals with this.

In short, the GUI actually updates only after the method ends its calculations (by which time it has gotten something on the order of 50 - 100 reloadData or setNeedsDisplay messages) rather then each time the "setNeedsDisplay" or "reloadData" method is called.

In debugging, the Controller is getting the "updateTheTable" method call from the model (the program stops at the break point set there), and is sending the "reloadData" message to the NSTableView in the Viewer, but nothing happens in the viewer until the main method stops and the viewer goes back to idly waiting for me to do something. I need to get the intermediate results displayed rather than the final results.

While this may be a bit vague, I am hoping someone recognizes my problem without me trying to post the entire program or me making a mock miniature program that accurately duplicates the problem.

Thanks in advance
 

HiRez

macrumors 603
Jan 6, 2004
6,250
2,576
Western US
You could try calling display: instead of setNeedsDisplay:, which should force a refresh, but this is probably wasteful and will not solve your problem.

What you really want is probably to spin your processing off to a separate thread and periodically call for UI updates on the main thread, which then should not block.
 

Catfish_Man

macrumors 68030
Sep 13, 2001
2,579
2
Portland, OR
Or do the work in chunks. Something like (totally untested)

Code:
- (void) doWorkChunk {
     /*
      do a few % of the work 
     */
     [view setNeedsDisplay:YES];
     [self performSelector:@selector(doWorkChunk) afterDelay:0]; //do another chunk of work on the next runloop iteration
}
 

binkmail

macrumors member
Jan 5, 2010
30
0
Or do your load work in a separate thread. (be sure to call setNeedsDisplay: from your main thread, though). Because AFAIK your windows/controls will not update until the RunLoop regains control of your application (ie. you are done doing your work) hence the behavior as described by you is normal.
 

Sydde

macrumors 68030
Aug 17, 2009
2,552
7,050
IOKWARDI
Or you could use NSTimer to break the operation up along the main run loop. Set up a work queue that checks for work every 5 milliseconds or so and do a few operations before returning. Somewhat less of a hassle than threading.
 

jctj

macrumors newbie
Original poster
Feb 24, 2010
18
0
By way of feedback:

@HiRez: display: worked great for the NSLevelIndicator, but did not work for the NSTableView (I know you said it wouldn't work, but I had to try...). Strange that the NSTableView did not do its update when sent the display: message.

@Catfish: Great idea, but won't work for details buried in the rest of the program, that were not mentioned in the OP. I'll keep that trick in mind for future problems.

@All: I'll be looking into threads next, as that is something I want to learn more about anyway. I will also check out using the NSTimer in case this makes for an easier/faster solution while I work on learning threads.
 

Sydde

macrumors 68030
Aug 17, 2009
2,552
7,050
IOKWARDI
It is fairly easy to just fire up a thread with +detachNewThreadSelector:toTarget:withObject: (NSThread class method), run through the process and then just exit, killing the thread. You can communicate with the main run loop with NSObject's -performSelectorOnMainThread:withObject:waitUntilDone: to make your display update, and use a simple boolean flag to signal a cancel, if you need that function as well.

The most important thing you need to remember is to create an autorelease pool for the thread and, if you are using a lot of autoreleased objects in the thread, to drain and recreate it from time to time.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.