![]() |
API 0.9.5
|
00001 /* 00002 * CPOperationQueue.j 00003 * 00004 * Created by Johannes Fahrenkrug. 00005 * Copyright 2009, Springenwerk. 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 00023 // the global queue (mainQueue) 00024 var cpOperationMainQueue = nil; 00025 00030 @implementation CPOperationQueue : CPObject 00031 { 00032 CPArray _operations; 00033 BOOL _suspended; 00034 CPString _name; 00035 CPTimer _timer; 00036 } 00037 00038 - (id)init 00039 { 00040 self = [super init]; 00041 00042 if (self) 00043 { 00044 _operations = [[CPArray alloc] init]; 00045 _suspended = NO; 00046 _currentlyModifyingOps = NO; 00047 _timer = [CPTimer scheduledTimerWithTimeInterval:0.01 00048 target:self 00049 selector:@selector(_runNextOpsInQueue) 00050 userInfo:nil 00051 repeats:YES]; 00052 } 00053 return self; 00054 } 00055 00056 - (void)_runNextOpsInQueue 00057 { 00058 if (!_suspended && [self operationCount] > 0) 00059 { 00060 var i = 0, 00061 count = [_operations count]; 00062 00063 for (; i < count; i++) 00064 { 00065 var op = [_operations objectAtIndex:i]; 00066 if ([op isReady] && ![op isCancelled] && ![op isFinished] && ![op isExecuting]) 00067 { 00068 [op start]; 00069 } 00070 } 00071 } 00072 } 00073 00074 - (void)_enableTimer:(BOOL)enable 00075 { 00076 if (!enable) 00077 { 00078 if (_timer) 00079 { 00080 [_timer invalidate]; 00081 _timer = nil; 00082 } 00083 } 00084 else 00085 { 00086 if (!_timer) 00087 { 00088 _timer = [CPTimer scheduledTimerWithTimeInterval:0.01 00089 target:self 00090 selector:@selector(_runNextOpsInQueue) 00091 userInfo:nil 00092 repeats:YES]; 00093 } 00094 } 00095 } 00096 00101 - (void)addOperation:(CPOperation)anOperation 00102 { 00103 [self willChangeValueForKey:@"operations"]; 00104 [self willChangeValueForKey:@"operationCount"]; 00105 [_operations addObject:anOperation]; 00106 [self _sortOpsByPriority:_operations]; 00107 [self didChangeValueForKey:@"operations"]; 00108 [self didChangeValueForKey:@"operationCount"]; 00109 } 00110 00116 - (void)addOperations:(CPArray)ops waitUntilFinished:(BOOL)wait 00117 { 00118 if (ops) 00119 { 00120 if (wait) 00121 { 00122 [self _sortOpsByPriority:ops]; 00123 [self _runOpsSynchronously:ops]; 00124 } 00125 00126 [_operations addObjectsFromArray:ops]; 00127 [self _sortOpsByPriority:_operations]; 00128 } 00129 } 00130 00135 - (void)addOperationWithFunction:(JSObject)aFunction 00136 { 00137 [self addOperation:[CPFunctionOperation functionOperationWithFunction:aFunction]]; 00138 } 00139 00140 - (CPArray)operations 00141 { 00142 return _operations; 00143 } 00144 00145 - (int)operationCount 00146 { 00147 if (_operations) 00148 { 00149 return [_operations count]; 00150 } 00151 00152 return 0; 00153 } 00154 00158 - (void)cancelAllOperations 00159 { 00160 if (_operations) 00161 { 00162 var i = 0, 00163 count = [_operations count]; 00164 00165 for (; i < count; i++) 00166 { 00167 [[_operations objectAtIndex:i] cancel]; 00168 } 00169 } 00170 } 00171 00175 - (void)waitUntilAllOperationsAreFinished 00176 { 00177 // lets first stop the timer so it won't interfere 00178 [self _enableTimer:NO]; 00179 [self _runOpsSynchronously:_operations]; 00180 if (!_suspended) 00181 { 00182 [self _enableTimer:YES]; 00183 } 00184 } 00185 00186 00191 - (int)maxConcurrentOperationCount 00192 { 00193 return 1; 00194 } 00195 00200 - (void)setSuspended:(BOOL)suspend 00201 { 00202 _suspended = suspend; 00203 [self _enableTimer:!suspend]; 00204 } 00205 00209 - (BOOL)isSuspended 00210 { 00211 return _suspended; 00212 } 00213 00214 - (void)_sortOpsByPriority:(CPArray)someOps 00215 { 00216 if (someOps) 00217 { 00218 [someOps sortUsingFunction:function(lhs, rhs) 00219 { 00220 if ([lhs queuePriority] < [rhs queuePriority]) 00221 { 00222 return 1; 00223 } 00224 else 00225 { 00226 if ([lhs queuePriority] > [rhs queuePriority]) 00227 { 00228 return -1; 00229 } 00230 else 00231 { 00232 return 0; 00233 } 00234 } 00235 } 00236 context:nil]; 00237 } 00238 } 00239 00240 - (void)_runOpsSynchronously:(CPArray)ops 00241 { 00242 if (ops) 00243 { 00244 var keepGoing = YES; 00245 while (keepGoing) 00246 { 00247 var i = 0, 00248 count = [ops count]; 00249 00250 keepGoing = NO; 00251 00252 // start the ones that are ready 00253 for (; i < count; i++) 00254 { 00255 var op = [ops objectAtIndex:i]; 00256 if ([op isReady] && ![op isCancelled] && ![op isFinished] && ![op isExecuting]) 00257 { 00258 [op start]; 00259 } 00260 } 00261 00262 // make sure they are all done 00263 for (i = 0; i < count; i++) 00264 { 00265 var op = [ops objectAtIndex:i]; 00266 if (![op isFinished] && ![op isCancelled]) 00267 { 00268 keepGoing = YES; 00269 } 00270 } 00271 } 00272 } 00273 } 00274 00278 + (CPOperationQueue)mainQueue 00279 { 00280 if (!cpOperationMainQueue) 00281 { 00282 cpOperationMainQueue = [[CPOperationQueue alloc] init]; 00283 [cpOperationMainQueue setName:@"main"]; 00284 } 00285 00286 return cpOperationMainQueue; 00287 } 00288 00292 + (CPOperationQueue)currentQueue 00293 { 00294 return [CPOperationQueue mainQueue]; 00295 } 00296 00297 @end 00298 00299 @implementation CPOperationQueue (CPSynthesizedAccessors) 00300 00304 - (CPString)name 00305 { 00306 return _name; 00307 } 00308 00312 - (void)setName:(CPString)aValue 00313 { 00314 _name = aValue; 00315 } 00316 00317 @end