You should not perform tasks that require a lot of processing time in the main event loop. This is what you do, and the entire user interface of the application will be blocked during the execution of your code. Locking the main thread is causing the "Rotating Pizza of Death". In other words, do not do this.
What you need to do is break your time-consuming code so that it works in another thread, that is, simultaneously in the background. When the background task completes, it should somehow notify the code running in the main thread that it completed. Your code in the main thread can then update the interface accordingly.
There are many ways to do this.
You can use the NSThread methods suggested by Randy Marsh. However, you must be very careful to read the documentation, as you cannot just call any old method in the background thread and expect it to work. You must create your own auto-resource pool in the stream and properly manage it. You should not call any methods that update the user interface from the secondary stream. You must be extremely careful that no variables are accessed or changed more than one thread at a time. Threading is a complex business.
The -performSelectorInBackground:withObject: NSObject is essentially a simple way to use NSThread and has the same caveats.
You can use the NSOperation and NSOperationQueue , which are especially good if you can break your task into small pieces that can be executed at the same time.
The easiest way to deal with this is GCD (Grand Central Dispatch) , which allows you to use built-in blocks to record background processes:
- (IBAction)taskTriggeredByNSButtonPress:(id)sender { [ibOutletToNSButton setEnabled:NO];
GCD is very lightweight and effective, and I highly recommend that you use it if possible.
Apple has more information and details about the Concurrency Programming Guide , which I recommend you read, although some details may be outside of you at this point.