Message Passing
The Foundation Framework NSObject class includes a collection of methods that use the message-passing paradigm to invoke a method on an object with a thread. The thread can be an existing secondary thread or the main application thread. The method selectors are
- performSelector:onThread:withObject:waitUntilDone:
- performSelector:onThread:withObject:waitUntilDone:modes:
- performSelectorOnMainThread:withObject:waitUntilDone:
- performSelectorOnMainThread:withObject:waitUntilDone:modes:
Each method specifies a selector for a method on the receiver object that will be invoked with a thread. This method is also known as a thread entry-point routine. The selector message is queued on the run loop of the thread, and the method is executed on the thread as part of the run loop’s standard processing. These message-passing methods enable you to specify whether the thread is invoked asynchronously or synchronously. Synchronous invocation results in the current thread blocking until the method finishes execution. Because these methods are defined for the NSObject class, they are provided for all classes that descend from NSObject (i.e., the majority of the Foundation Framework APIs and most of the custom classes that you will implement). Listing 17-3 depicts use of theperformSelector:onThread: method to asynchronously invoke the downloadTask method on a thread named secondaryThread, where this method is defined for a custom class named ConcurrentProcessor.
Listing 17-3. NSObject performSelector:onThread:withObject:waitUntilDone: Method Invocation
ConcurrentProcessor *processor = [ConcurrentProcessor new];
[processor performSelector:@selector(downloadTask)
onThread:secondaryThread
withObject:nil
waitUntilDone:NO];
As shown in Listing 17-3, the waitUntilDone: parameter specifies asynchronous/synchronous operation. In this example, the input value is set to NO, thus the current thread returns immediately.
When you create a thread, you can configure portions of its runtime environment (e.g., stack size, thread-local storage, thread priority, etc.). It is also important to configure the thread context appropriately by implementing the thread entry-point routine with the following functionality (as necessary):
- An autorelease pool: An autorelease pool should be created at the beginning of the entry-point routine, and destroyed at the end of the routine.
- An exception handler: If the application catches and handles exceptions, the entry-point routine should be configured to catch any exceptions that can occur. Chapter 14 discusses the Objective-C mechanisms for exception handling.
- A run loop: In order to have a thread process requests dynamically as they arrive, you can setup a run loop in the entry-point routine. Chapter 11 covers the use of the Foundation Framework NSRunLoop class.
Listing 17-4, the ConcurrentProcessor downloadTask method, demonstrates implementation of an entry-point routine per the guidelines documented earlier.
Listing 17-4. ConcurrentProcessor downloadTask Method
@implementation ConcurrentProcessor
...
- (void)downloadTask
{
@autoreleasepool
{
NSURL *url = [NSURL URLWithString:@"http://www.apress.com
"];
NSString *str = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding
error:nil];
NSLog(@"URL Contents:\n%@", str);
self.isLoaded = YES;
}
}
@end
The NSObject performSelectorOnMainThread: methods are typically used to return values (status, results, etc.) f