Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
242 lines (205 sloc) 8.99 KB
//
// ThreadedTask 0.3
// Perform a long task without blocking the main thread.
//
// Copyright (c) 2004-2005, Charles McGarvey
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list
// of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
//
#import <Cocoa/Cocoa.h>
@interface ThreadedTask : NSObject
{
// task objects
id _target;
SEL _selector;
int (*_function)(id, unsigned);
id _context;
// keeping track of things...
BOOL _isTaskThreadRunning;
BOOL _doCancelTask;
// the delegate object
id _delegate;
NSRunLoop *_runloop;
NSArray *_modes;
// locks
NSLock *_taskLock;
}
// #############################################################################
#pragma mark Initialization
// #############################################################################
/* See accessor methods for a description of the parameters. */
- (id)initWithTarget:(id)target selector:(SEL)selector delegate:(id)delegate;
- (id)initWithTarget:(id)target selector:(SEL)selector context:(id)context delegate:(id)delegate;
- (id)initWithFunction:(int (*)(ThreadedTask *, unsigned))function delegate:(id)delegate;
- (id)initWithFunction:(int (*)(ThreadedTask *, unsigned))function context:(id)context delegate:(id)delegate;
// #############################################################################
#pragma mark Accessor Methods
// #############################################################################
/*
* As a protection, it is not possible to change the iteration method or function,
* or the context while the task is running.
*/
/*
* The target is the object (or class) that the selector is used on. Target is
* not retained.
*
* The selector which should be used should be in this form:
*
* - (int)task:(ThreadedTask *)task iteration:(unsigned)iteration;
*
* The task parameter is the ThreadedTask object belonging to the task.
* The iteration parameter increases by one for each iteration that passes.
*
* The return value is the important part. It's what tells task object
* whether to continue or stop or report a failure. Here are the values:
*
* Returning 1 means the task is not finished, and the iteration method
* or function will be called again.
* Returning 0 means the task is finished, and to end it.
* Returning _anything_ else and the task will assume it is an error code;
* the task would then abort and report the error code to the delegate.
*
* The target and selector will be set to nil if either are not valid.
*/
- (id)target;
- (SEL)selector;
- (void)setTarget:(id)target selector:(SEL)selector;
/*
* A function can be used instead of a target and selector. The function
* should be in the following form:
*
* int MyTask( ThreadedTask *task, unsigned iteration );
*
* The parameters and return value are the same as for the selector. The
* task uses the function if setFunction: was called after setTarget:, or
* if setTarget: was never called.
*/
- (int (*)(id, unsigned))function;
- (void)setFunction:(int (*)(id, unsigned))function;
/*
* The context of the threaded task can be any object. It is set before
* the task is run. The iteration method/function can retrieve this
* context from the task and use it to safely store results from the
* task. The context can also be nil if the iteration doesn't need it.
*/
- (id)context;
- (void)setContext:(id)context;
/*
* Delegation is how information is received from the task. Setting a
* delegate isn't required, but it's pointless not to do so. Unlike
* the above accessors, the delegate can be changed while a task is running.
* A runloop can also be specified which is used to send the delegate
* methods using the given modes. If no runloop is specified, the current
* runloop for the thread which runs the threaded task is used. Neither
* the delegate or the runloop are retained, but the modes are. If a
* runloop is not specified and there is no current runloop, then no delegate
* methods will be sent. Pass nil for modes to use the mode of the current
* runloop.
*/
- (id)delegate;
- (void)setDelegate:(id)delegate;
- (void)setDelegateRunLoop:(NSRunLoop *)runloop modes:(NSArray *)modes;
/*
* Returns YES if the thread is detached and the task is being performed.
*/
- (BOOL)isRunning;
// #############################################################################
#pragma mark Control Methods
// #############################################################################
/*
* Begin execution of the task. This method returns immediately.
* The delegate will recieve threadedTaskFinished: when the task has completed
* its purpose. This method will return YES if the task was successfully
* started, and NO if the task could not be run, which usually occurs if the
* iteration method/selector or function is not valid.
*/
- (BOOL)run;
/*
* General information about cancelling: If you release the ThreadedTask object
* while a task is running, the task will be cancelled for you automatically
* and this is generally safe to do, but the release may block the main thread
* for a short amount of time while the task cancels. This can be avoided by
* using a cancel method below which doesn't block.
*/
/*
* Signal the task to cancel prematurely. This method will block until the
* task actually does cancel. It is safe to release the ThreadedTask object
* any time after this call without blocking. If the iteration method or
* function is blocking for some reason, you should used a different cancel
* method which doesn't block, otherwise a deadlock could occur.
*/
- (void)cancel;
/*
* Signal the task to cancel prematurely. This method returns immediately, but
* you should not release the ThreadedTask object until the delegate receives
* a conclusion method.
*/
- (void)cancelWithoutWaiting;
/*
* Signal the task to cancel prematurely. This is a convenience method that
* sets the delegate to nil and cancels the task without blocking at the same
* time. This is useful if the delegate is going to be released while the task
* is running. You should not release the ThreadedTask object immediately
* after this call, but you will also not receive any notification that it is
* safe to do so. You will know when receiver can be released without blocking
* when the isRunning method returns NO.
*/
- (void)cancelAndRemoveDelegate;
// #############################################################################
#pragma mark Iteration Methods
// #############################################################################
/*
* Report progress of the task back to the main thread. This method should only
* be called from the iteration method or function. It takes a single integer
* parameter which can be anything the receiver of the progress report will
* understand (perhaps 0 thru 100, like as a percentage).
*/
- (void)reportProgress:(int)progress;
@end
@interface NSObject ( ThreadedTaskDelegate )
// #############################################################################
#pragma mark Delegate Methods
// #############################################################################
/*
* These delegate methods are sent on the thread running the delegate runloop,
* or the main runloop if none is specified. It is typically safe to update
* the user interface from these methods.
*/
/*
* Sent to the delegate upon completion of the task.
*/
- (void)threadedTaskFinished:(ThreadedTask *)theTask;
/*
* Sent to the delegate when the task has finished cancelling.
*/
- (void)threadedTaskCancelled:(ThreadedTask *)theTask;
/*
* Sent to the delegate when the iteration returned an error.
*/
- (void)threadedTask:(ThreadedTask *)theTask failedWithErrorCode:(int)errorCode;
/*
* Sent to the delegate to report the progress of the task. This is a direct
* result of the reportProgress: method being called from the iteration.
*/
- (void)threadedTask:(ThreadedTask *)theTask reportedProgress:(int)theProgress;
@end
Jump to Line
Something went wrong with that request. Please try again.