Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 242 lines (205 sloc) 9.208 kb
d27548f @chazmcgarvey The Cheat 1.2
chazmcgarvey authored
1
2 //
3 // ThreadedTask 0.3
4 // Perform a long task without blocking the main thread.
5 //
556707a @chazmcgarvey The Cheat 1.2.5
chazmcgarvey authored
6 // Copyright (c) 2004-2005, Charles McGarvey
d27548f @chazmcgarvey The Cheat 1.2
chazmcgarvey authored
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without modification, are
10 // permitted provided that the following conditions are met:
11 //
12 // 1. Redistributions of source code must retain the above copyright notice, this list
13 // of conditions and the following disclaimer.
14 //
15 // 2. Redistributions in binary form must reproduce the above copyright notice, this
16 // list of conditions and the following disclaimer in the documentation and/or other
17 // materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22 // SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28 // DAMAGE.
29 //
30
31 #import <Cocoa/Cocoa.h>
32
33
34 @interface ThreadedTask : NSObject
35 {
36 // task objects
37 id _target;
38 SEL _selector;
39 int (*_function)(id, unsigned);
40 id _context;
41 // keeping track of things...
42 BOOL _isTaskThreadRunning;
43 BOOL _doCancelTask;
44 // the delegate object
45 id _delegate;
46 NSRunLoop *_runloop;
47 NSArray *_modes;
48 // locks
49 NSLock *_taskLock;
50 }
51
52 // #############################################################################
53 #pragma mark Initialization
54 // #############################################################################
55
56 /* See accessor methods for a description of the parameters. */
57 - (id)initWithTarget:(id)target selector:(SEL)selector delegate:(id)delegate;
58 - (id)initWithTarget:(id)target selector:(SEL)selector context:(id)context delegate:(id)delegate;
44e9757 @chazmcgarvey The Cheat 1.2.1
chazmcgarvey authored
59 - (id)initWithFunction:(int (*)(ThreadedTask *, unsigned))function delegate:(id)delegate;
60 - (id)initWithFunction:(int (*)(ThreadedTask *, unsigned))function context:(id)context delegate:(id)delegate;
d27548f @chazmcgarvey The Cheat 1.2
chazmcgarvey authored
61
62
63 // #############################################################################
64 #pragma mark Accessor Methods
65 // #############################################################################
66
67 /*
68 * As a protection, it is not possible to change the iteration method or function,
69 * or the context while the task is running.
70 */
71
72 /*
73 * The target is the object (or class) that the selector is used on. Target is
74 * not retained.
75 *
76 * The selector which should be used should be in this form:
77 *
78 * - (int)task:(ThreadedTask *)task iteration:(unsigned)iteration;
79 *
80 * The task parameter is the ThreadedTask object belonging to the task.
81 * The iteration parameter increases by one for each iteration that passes.
82 *
83 * The return value is the important part. It's what tells task object
84 * whether to continue or stop or report a failure. Here are the values:
85 *
86 * Returning 1 means the task is not finished, and the iteration method
87 * or function will be called again.
88 * Returning 0 means the task is finished, and to end it.
89 * Returning _anything_ else and the task will assume it is an error code;
90 * the task would then abort and report the error code to the delegate.
91 *
92 * The target and selector will be set to nil if either are not valid.
93 */
94 - (id)target;
95 - (SEL)selector;
96 - (void)setTarget:(id)target selector:(SEL)selector;
97
98 /*
99 * A function can be used instead of a target and selector. The function
100 * should be in the following form:
101 *
102 * int MyTask( ThreadedTask *task, unsigned iteration );
103 *
104 * The parameters and return value are the same as for the selector. The
105 * task uses the function if setFunction: was called after setTarget:, or
106 * if setTarget: was never called.
107 */
108
109 - (int (*)(id, unsigned))function;
110 - (void)setFunction:(int (*)(id, unsigned))function;
111
112 /*
113 * The context of the threaded task can be any object. It is set before
114 * the task is run. The iteration method/function can retrieve this
115 * context from the task and use it to safely store results from the
116 * task. The context can also be nil if the iteration doesn't need it.
117 */
118 - (id)context;
119 - (void)setContext:(id)context;
120
121 /*
122 * Delegation is how information is received from the task. Setting a
123 * delegate isn't required, but it's pointless not to do so. Unlike
124 * the above accessors, the delegate can be changed while a task is running.
125 * A runloop can also be specified which is used to send the delegate
126 * methods using the given modes. If no runloop is specified, the current
127 * runloop for the thread which runs the threaded task is used. Neither
128 * the delegate or the runloop are retained, but the modes are. If a
129 * runloop is not specified and there is no current runloop, then no delegate
130 * methods will be sent. Pass nil for modes to use the mode of the current
131 * runloop.
132 */
133 - (id)delegate;
134 - (void)setDelegate:(id)delegate;
135 - (void)setDelegateRunLoop:(NSRunLoop *)runloop modes:(NSArray *)modes;
136
137 /*
138 * Returns YES if the thread is detached and the task is being performed.
139 */
140 - (BOOL)isRunning;
141
142
143 // #############################################################################
144 #pragma mark Control Methods
145 // #############################################################################
146
147 /*
148 * Begin execution of the task. This method returns immediately.
149 * The delegate will recieve threadedTaskFinished: when the task has completed
150 * its purpose. This method will return YES if the task was successfully
151 * started, and NO if the task could not be run, which usually occurs if the
152 * iteration method/selector or function is not valid.
153 */
154 - (BOOL)run;
155
156 /*
157 * General information about cancelling: If you release the ThreadedTask object
158 * while a task is running, the task will be cancelled for you automatically
159 * and this is generally safe to do, but the release may block the main thread
160 * for a short amount of time while the task cancels. This can be avoided by
161 * using a cancel method below which doesn't block.
162 */
163
164 /*
165 * Signal the task to cancel prematurely. This method will block until the
166 * task actually does cancel. It is safe to release the ThreadedTask object
167 * any time after this call without blocking. If the iteration method or
168 * function is blocking for some reason, you should used a different cancel
169 * method which doesn't block, otherwise a deadlock could occur.
170 */
171 - (void)cancel;
172
173 /*
174 * Signal the task to cancel prematurely. This method returns immediately, but
175 * you should not release the ThreadedTask object until the delegate receives
176 * a conclusion method.
177 */
178 - (void)cancelWithoutWaiting;
179
180 /*
181 * Signal the task to cancel prematurely. This is a convenience method that
182 * sets the delegate to nil and cancels the task without blocking at the same
183 * time. This is useful if the delegate is going to be released while the task
184 * is running. You should not release the ThreadedTask object immediately
185 * after this call, but you will also not receive any notification that it is
186 * safe to do so. You will know when receiver can be released without blocking
187 * when the isRunning method returns NO.
188 */
189 - (void)cancelAndRemoveDelegate;
190
191
192 // #############################################################################
193 #pragma mark Iteration Methods
194 // #############################################################################
195
196 /*
197 * Report progress of the task back to the main thread. This method should only
198 * be called from the iteration method or function. It takes a single integer
199 * parameter which can be anything the receiver of the progress report will
200 * understand (perhaps 0 thru 100, like as a percentage).
201 */
202 - (void)reportProgress:(int)progress;
203
204 @end
205
206
207 @interface NSObject ( ThreadedTaskDelegate )
208
209 // #############################################################################
210 #pragma mark Delegate Methods
211 // #############################################################################
212
213 /*
214 * These delegate methods are sent on the thread running the delegate runloop,
215 * or the main runloop if none is specified. It is typically safe to update
216 * the user interface from these methods.
217 */
218
219 /*
220 * Sent to the delegate upon completion of the task.
221 */
222 - (void)threadedTaskFinished:(ThreadedTask *)theTask;
223
224 /*
225 * Sent to the delegate when the task has finished cancelling.
226 */
227 - (void)threadedTaskCancelled:(ThreadedTask *)theTask;
228
229 /*
230 * Sent to the delegate when the iteration returned an error.
231 */
232 - (void)threadedTask:(ThreadedTask *)theTask failedWithErrorCode:(int)errorCode;
233
234 /*
235 * Sent to the delegate to report the progress of the task. This is a direct
236 * result of the reportProgress: method being called from the iteration.
237 */
238 - (void)threadedTask:(ThreadedTask *)theTask reportedProgress:(int)theProgress;
239
240 @end
241
Something went wrong with that request. Please try again.