views:

234

answers:

1

following is .m code:

#import "ThreadLabAppDelegate.h"
@interface ThreadLabAppDelegate()

- (void)processStart;
- (void)processCompleted;

@end


@implementation ThreadLabAppDelegate

@synthesize isProcessStarted;

- (void)awakeFromNib {
    //Set levelindicator's maximum value
    [levelIndicator setMaxValue:1000];
}

- (void)dealloc {
    //Never called while debugging ????
    [super dealloc];
}

- (IBAction)startProcess:(id)sender {
    //Set process flag to true
    self.isProcessStarted=YES;

    //Start Animation
    [spinIndicator startAnimation:nil];

    //perform selector in background thread
    [self performSelectorInBackground:@selector(processStart) withObject:nil];
}

- (IBAction)stopProcess:(id)sender {
    //Stop Animation
    [spinIndicator stopAnimation:nil];

    //set process flag to false
    self.isProcessStarted=NO;
}

- (void)processStart {
    int counter = 0;
    while (counter != 1000) {
        NSLog(@"Counter : %d",counter);

        //Sleep background thread to reduce CPU usage
        [NSThread sleepForTimeInterval:0.01];

        //set the level indicator value to showing progress
        [levelIndicator setIntValue:counter];

        //increment counter
        counter++;
    }

    //Notify main thread for process completed
    [self performSelectorOnMainThread:@selector(processCompleted) withObject:nil waitUntilDone:NO];

}

- (void)processCompleted {
    //Stop Animation
    [spinIndicator stopAnimation:nil];

    //set process flag to false
    self.isProcessStarted=NO;
}
@end 

I need to clear following things as per the above code.

  1. How to interrupt/cancel processStart while loop from UI control?
  2. I also need to show the counter value in main UI, which i suppose to do with performSelectorOnMainThread and passing argument. Just want to know, is there anyother way to do that?
  3. When my app started it is showing 1 thread in Activity Monitor, but when i started the processStart() in background thread its creating two new thread,which makes the total 3 thread until or unless loop get finished.After completing the loop i can see 2 threads. So, my understanding is that, 2 thread created when i called performSelectorInBackground, but what about the thrid thread, from where it got created?
  4. What if thread counts get increases on every call of selector.How to control that or my implementation is bad for such kind of requirements?

Thanks

+4  A: 

how to update UI controls in cocoa application from background thread

Simple: Don't.

How to interrupt/cancel processStart while loop from UI control?

Outside of processStart, set a flag variable. Inside of processStart, check that flag and exit the loop if it is set.

Don't try to “kill” a thread from another thread. It's always a bad idea. Tell the thread it's time to stop by setting the flag, and have the thread check that flag and stop at an appropriate time.

I also need to show the counter value in main UI, which i suppose to do with performSelectorOnMainThread and passing argument. Just want to know, is there anyother way to do that?

Yes.

When my app started it is showing 1 thread in Activity Monitor, but when i started the processStart() in background thread its creating two new thread,which makes the total 3 thread until or unless loop get finished.After completing the loop i can see 2 threads. So, my understanding is that, 2 thread created when i called performSelectorInBackground, but what about the thrid thread, from where it got created?

Profile your app using Instruments or Shark and look. It's probably the heartbeat thread for the progress indicator.

What if thread counts get increases on every call of selector.How to control that or my implementation is bad for such kind of requirements?

Every performSelectorInBackground:withObject: message starts a thread. If your thread count isn't going down, it's because your thread method didn't exit. If your thread count is too high, it's (probably) because you started too many threads.


There is a much better way to do this.

First, the general rule in Cocoa is never sleep. Think of this as special ultra-caffeinated Cocoa. For anything you might sleep for in another framework, there is almost always a better, usually easier, way in Cocoa.

With that in mind, look at processStart. All it does is do something every centisecond. How best to do that?

Cocoa has a class for this specific purpose: NSTimer. Create a timer that sends yourself a message at the desired interval, and respond to that message by updating the progress bar—that is, your timer callback method should essentially just be the loop body from processStart, without the loop.

By the way, 100 updates per second is overkill. First off, the user does not care that you have made 1/5th of a pixel's worth of progress since the last time you updated the bar. Second, the screen only updates about 60 times per second anyway, so updating anything visible faster than that is pointless.

- (void)dealloc {
    //Never called while debugging ????
    [super dealloc];
}

Assuming you put your app delegate in the MainMenu nib, the application object owns it because of that—but it doesn't know that, because it only knows about the app delegate as its delegate, which is a non-owning relationship. (And even if it were an owning relationship, that would just be two ownerships, of which the app would release one, which wouldn't help.)

However, the lifetime of the app delegate doesn't really matter. Its purpose as the delegate of the application means that it needs to last about as long as the application does, but when the application goes away, the process is exiting, which means the delegate will be deallocated as well, as part of the reclamation of the process's memory space. That's why dealloc isn't called—the whole process space goes away at once, instead of objects being deallocated one at a time.

So, in principle, yeah, the app delegate not getting explicitly cleaned up is kind of dodgy. In practice, don't put any temporary-files clean-up in its dealloc (use applicationWillTerminate: instead) and you'll be fine.

I typically work around the problem by putting all my real work in one or more other objects which the app delegate owns. The app delegate creates these other controllers in applicationWillFinishLaunching: and releases them in applicationWillTerminate:, so those objects do get dealloc messages. Problem solved.

Peter Hosey
once again thanks for providing me clear picture of cocoa and its meaningful usage in programming. I further want to explain my requirements related with my questions and code. I am working on Tool which required to search files/folders in file system. Normally, i don't need to care about the time taken by recursive search on selected folder. But, when user trying to search one of the root folder, then application goes in deep loop due to recursive search on sub folders and its files. Also the UI get hanged.Continue...
AmitSri
I know showing progress is not so important for the users, but my tool require to show them some kind of progress and allow them to cancel the searching operation. My another question is related to set a flag variable to stop loop running in background thread, can we access the main controller flag variable or property in background thread? what about cross-thread operation or accessing variables and properties?
AmitSri
You really don't need, and shouldn't use, a thread to update the progress bar. On the contrary: You should use NSOperations, which each run on a thread, to walk the directory tree, and send yourself a main-thread message to update the progress, and respond to that message by updating any views (e.g., the progress bar) that indicate progress. (Warning about using NSOperations for purposes like this: http://www.mikeash.com/pyblog/friday-qa-2009-09-25-gcd-practicum.html )
Peter Hosey
Thanks, i got your point, besides the original requirement i need to know something more. I have raised my question in following link.http://stackoverflow.com/questions/2935007/difference-between-performselectorinbackground-and-nsoperation-subclass/2935285#2935285I also want to know your opinion and any suggestions. Apart from that i also want to thanks you for providing me link http://www.mikeash.com/pyblog/friday-qa-2009-09-25-gcd-practicum.html. It seems to be quite useful and i am trying to understand the implementation explained by the author.
AmitSri