@@ -65,14 +65,14 @@ public class TaskConfiguration
65
65
}
66
66
}
67
67
68
- // abstract class for `weak _parentTask`
68
+ // abstract class for `weak _parentTask` with arbitrary `Progress` & `Value` types
69
69
public class _Task < Error>
70
70
{
71
71
internal weak var _parentTask : _Task ?
72
72
73
73
internal let _weakified : Bool
74
74
75
- public init ( weakified: Bool ) { self . _weakified = weakified }
75
+ public init ( weakified: Bool , paused : Bool ) { self . _weakified = weakified }
76
76
public func pause( ) -> Bool { return true }
77
77
public func resume( ) -> Bool { return true }
78
78
public func cancel( error: Error ? = nil ) -> Bool { return true }
@@ -98,11 +98,14 @@ public class Task<Progress, Value, Error>: _Task<Error>
98
98
99
99
internal typealias Machine = StateMachine < TaskState , TaskEvent >
100
100
101
- internal var machine : Machine !
101
+ private var machine : Machine !
102
102
103
103
// store initial parameters for cloning task when using `try()`
104
104
internal var _initClosure : _InitClosure ? // will be nil on fulfilled/rejected
105
105
106
+ /// wrapper closure for `_initClosure` to invoke only once when started `.Running`
107
+ internal var _performInitClosure : ( Void -> Void ) ?
108
+
106
109
/// progress value
107
110
public internal( set) var progress : Progress ?
108
111
@@ -127,84 +130,109 @@ public class Task<Progress, Value, Error>: _Task<Error>
127
130
}
128
131
129
132
///
130
- /// Creates new task.
133
+ /// Creates a new task.
131
134
///
132
- /// - e.g. Task<P, V, E>(weakified: false) { progress, fulfill, reject, configure in ... }
135
+ /// - e.g. Task<P, V, E>(weakified: false, paused: false ) { progress, fulfill, reject, configure in ... }
133
136
///
134
137
/// :param: weakified Weakifies progress/fulfill/reject handlers to let player (inner asynchronous implementation inside initClosure) NOT CAPTURE this created new task. Normally, weakified = false should be set to gain "player -> task" retaining, so that task will be automatically deinited when player is deinited. If weakified = true, task must be manually retained somewhere else, or it will be immediately deinited.
135
138
///
139
+ /// :param: paused Flag to invoke `initClosure` immediately or not. If `paused = true`, task's initial state will be `.Paused` and needs to `resume()` in order to start `.Running`. If `paused = false`, `initClosure` will be invoked immediately.
140
+ ///
136
141
/// :param: initClosure e.g. { progress, fulfill, reject, configure in ... }. fulfill(value) and reject(error) handlers must be called inside this closure, where calling progress(progressValue) handler is optional. Also as options, configure.pause/resume/cancel closures can be set to gain control from outside e.g. task.pause()/resume()/cancel(). When using configure, make sure to use weak modifier when appropriate to avoid "task -> player" retaining which often causes retain cycle.
137
142
///
138
143
/// :returns: New task.
139
144
///
140
- public init ( weakified: Bool , initClosure: InitClosure )
145
+ public init ( weakified: Bool , paused : Bool , initClosure: InitClosure )
141
146
{
142
- super. init ( weakified: weakified)
147
+ super. init ( weakified: weakified, paused : paused )
143
148
144
149
let _initClosure : _InitClosure = { machine, progress, fulfill, _reject, configure in
145
150
// NOTE: don't expose rejectHandler with ErrorInfo (isCancelled) for public init
146
151
initClosure ( progress: progress, fulfill: fulfill, reject: { ( error: Error ? ) in _reject ( ErrorInfo ( error: error, isCancelled: false ) ) } , configure: configure)
147
- return
148
152
}
149
153
150
- self . setup ( weakified, _initClosure)
154
+ self . setup ( weakified, paused : paused , _initClosure)
151
155
}
152
156
153
- /// creates task without weakifying progress/fulfill/reject handlers
157
+ ///
158
+ /// creates a new task without weakifying progress/fulfill/reject handlers
159
+ ///
160
+ /// - e.g. Task<P, V, E>(paused: false) { progress, fulfill, reject, configure in ... }
161
+ ///
162
+ public convenience init ( paused: Bool , initClosure: InitClosure )
163
+ {
164
+ self . init ( weakified: false , paused: paused, initClosure: initClosure)
165
+ }
166
+
167
+ ///
168
+ /// creates a new task without weakifying progress/fulfill/reject handlers (non-paused)
169
+ ///
170
+ /// - e.g. Task<P, V, E> { progress, fulfill, reject, configure in ... }
171
+ ///
154
172
public convenience init ( initClosure: InitClosure )
155
173
{
156
- self . init ( weakified: false , initClosure: initClosure)
174
+ self . init ( weakified: false , paused : false , initClosure: initClosure)
157
175
}
158
176
159
- /// creates fulfilled task
177
+ ///
178
+ /// creates fulfilled task (non-paused)
179
+ ///
180
+ /// - e.g. Task<P, V, E>(value: someValue)
181
+ ///
160
182
public convenience init ( value: Value )
161
183
{
162
184
self . init ( initClosure: { progress, fulfill, reject, configure in
163
185
fulfill ( value)
164
- return
165
186
} )
166
187
}
167
188
168
- /// creates rejected task
189
+ ///
190
+ /// creates rejected task (non-paused)
191
+ ///
192
+ /// - e.g. Task<P, V, E>(error: someError)
193
+ ///
169
194
public convenience init ( error: Error )
170
195
{
171
196
self . init ( initClosure: { progress, fulfill, reject, configure in
172
197
reject ( error)
173
- return
174
198
} )
175
199
}
176
200
201
+ ///
177
202
/// creates promise-like task which only allows fulfill & reject (no progress & configure)
203
+ ///
204
+ /// - e.g. Task<Any, Value, Error> { fulfill, reject in ... }
205
+ ///
178
206
public convenience init ( promiseInitClosure: PromiseInitClosure )
179
207
{
180
208
self . init ( initClosure: { progress, fulfill, reject, configure in
181
209
promiseInitClosure ( fulfill: fulfill, reject: { ( error: Error ) in reject ( error) } )
182
- return
183
210
} )
184
211
}
185
212
186
- /// NOTE: _initClosure has _RejectHandler as argument
187
- internal init ( weakified: Bool = false , _initClosure: _InitClosure )
213
+ /// internal-init for accessing private `machine` inside `_initClosure`
214
+ /// (NOTE: _initClosure has _RejectHandler as argument)
215
+ internal init ( weakified: Bool = false , paused: Bool = false , _initClosure: _InitClosure )
188
216
{
189
- super. init ( weakified: weakified)
190
- self . setup ( weakified, _initClosure)
217
+ super. init ( weakified: weakified, paused : paused )
218
+ self . setup ( weakified, paused : paused , _initClosure)
191
219
}
192
220
193
- internal func setup( weakified: Bool , _initClosure: _InitClosure )
221
+ internal func setup( weakified: Bool , paused : Bool , _initClosure: _InitClosure )
194
222
{
195
223
// #if DEBUG
196
224
// println("[init] \(self)")
197
225
// #endif
198
226
199
- self . _initClosure = _initClosure
200
-
201
227
let configuration = Configuration ( )
202
228
229
+ let initialState : TaskState = paused ? . Paused : . Running
230
+
203
231
// NOTE: Swift 1.1 compiler fails if using [weak self] instead...
204
232
weak var weakSelf = self
205
233
206
234
// setup state machine
207
- self . machine = Machine ( state: . Running ) {
235
+ self . machine = Machine ( state: initialState ) {
208
236
209
237
$0. addRouteEvent ( . Pause, transitions: [ . Running => . Paused] )
210
238
$0. addRouteEvent ( . Resume, transitions: [ . Paused => . Running] )
@@ -245,97 +273,114 @@ public class Task<Progress, Value, Error>: _Task<Error>
245
273
// clear `_initClosure` & all StateMachine's handlers to prevent retain cycle
246
274
$0. addEventHandler ( . Fulfill, order: 255 ) { context in
247
275
weakSelf? . _initClosure = nil
276
+ weakSelf? . _performInitClosure = nil
248
277
weakSelf? . machine? . removeAllHandlers ( )
249
278
}
250
279
$0. addEventHandler ( . Reject, order: 255 ) { context in
251
280
weakSelf? . _initClosure = nil
281
+ weakSelf? . _performInitClosure = nil
252
282
weakSelf? . machine? . removeAllHandlers ( )
253
283
}
254
284
255
285
}
256
286
257
- var progressHandler : ProgressHandler
258
- var fulfillHandler : FulFillHandler
259
- var rejectHandler : _RejectHandler
287
+ self . _initClosure = _initClosure
260
288
261
- if weakified {
262
- progressHandler = { [ weak self] ( progress: Progress ) in
263
- if let self_ = self {
264
- let oldProgress = self_. progress
265
- self_. machine <-! ( . Progress, ( oldProgress, progress) )
266
- }
267
- }
289
+ // will be invoked only once
290
+ self . _performInitClosure = { [ weak self] in
268
291
269
- fulfillHandler = { [ weak self] ( value: Value ) in
270
- if let self_ = self {
271
- self_. machine <-! ( . Fulfill, value)
292
+ if let self_ = self {
293
+
294
+ var progressHandler : ProgressHandler
295
+ var fulfillHandler : FulFillHandler
296
+ var rejectHandler : _RejectHandler
297
+
298
+ if weakified {
299
+ progressHandler = { [ weak self_] ( progress: Progress ) in
300
+ if let self_ = self_ {
301
+ let oldProgress = self_. progress
302
+ self_. machine <-! ( . Progress, ( oldProgress, progress) )
303
+ }
304
+ }
305
+
306
+ fulfillHandler = { [ weak self_] ( value: Value ) in
307
+ if let self_ = self_ {
308
+ self_. machine <-! ( . Fulfill, value)
309
+ }
310
+ }
311
+
312
+ rejectHandler = { [ weak self_] ( errorInfo: ErrorInfo ) in
313
+ if let self_ = self_ {
314
+ self_. machine <-! ( . Reject, errorInfo)
315
+ }
316
+ }
272
317
}
273
- }
274
-
275
- rejectHandler = { [ weak self] ( errorInfo: ErrorInfo ) in
276
- if let self_ = self {
277
- self_. machine <-! ( . Reject, errorInfo)
318
+ else {
319
+ progressHandler = { ( progress: Progress ) in
320
+ let oldProgress = self_. progress
321
+ self_. machine <-! ( . Progress, ( oldProgress, progress) )
322
+ return
323
+ }
324
+
325
+ fulfillHandler = { ( value: Value ) in
326
+ self_. machine <-! ( . Fulfill, value)
327
+ return
328
+ }
329
+
330
+ rejectHandler = { ( errorInfo: ErrorInfo ) in
331
+ self_. machine <-! ( . Reject, errorInfo)
332
+ return
333
+ }
278
334
}
279
- }
280
- }
281
- else {
282
- progressHandler = { ( progress: Progress ) in
283
- let oldProgress = self . progress
284
- self . machine <-! ( . Progress, ( oldProgress, progress) )
285
- return
286
- }
287
335
288
- fulfillHandler = { ( value: Value ) in
289
- self . machine <-! ( . Fulfill, value)
290
- return
291
- }
292
-
293
- rejectHandler = { ( errorInfo: ErrorInfo ) in
294
- self . machine <-! ( . Reject, errorInfo)
295
- return
296
- }
297
- }
298
-
299
- _initClosure ( machine: self . machine, progress: progressHandler, fulfill: fulfillHandler, _reject: rejectHandler, configure: configuration)
300
-
301
- let userPauseClosure = configuration. pause
302
- let userResumeClosure = configuration. resume
303
- let userCancelClosure = configuration. cancel
304
-
305
- // add parentTask-pause/resume/cancel functionalities after retrieving user-defined configuration
306
- configuration. pause = { [ weak self] in
307
- userPauseClosure ? ( )
308
-
309
- var task : _Task ? = self
310
- while let parentTask = task? . _parentTask {
311
- if parentTask. _weakified { break }
336
+ _initClosure ( machine: self_. machine, progress: progressHandler, fulfill: fulfillHandler, _reject: rejectHandler, configure: configuration)
312
337
313
- parentTask. pause ( )
314
- task = parentTask
315
- }
316
-
317
- }
318
- configuration. resume = { [ weak self] in
319
- userResumeClosure ? ( )
320
-
321
- var task : _Task ? = self
322
- while let parentTask = task? . _parentTask {
323
- if parentTask. _weakified { break }
338
+ let userPauseClosure = configuration. pause
339
+ let userResumeClosure = configuration. resume
340
+ let userCancelClosure = configuration. cancel
324
341
325
- parentTask. resume ( )
326
- task = parentTask
327
- }
328
- }
329
- configuration. cancel = { [ weak self] in
330
- userCancelClosure ? ( )
331
-
332
- var task : _Task ? = self
333
- while let parentTask = task? . _parentTask {
334
- if parentTask. _weakified { break }
342
+ // add parentTask-pause/resume/cancel functionalities after retrieving user-defined configuration
343
+ configuration. pause = { [ weak self_] in
344
+ userPauseClosure ? ( )
345
+
346
+ var task : _Task ? = self_
347
+ while let parentTask = task? . _parentTask {
348
+ if parentTask. _weakified { break }
349
+
350
+ parentTask. pause ( )
351
+ task = parentTask
352
+ }
353
+
354
+ }
355
+ configuration. resume = { [ weak self_] in
356
+ userResumeClosure ? ( )
357
+
358
+ var task : _Task ? = self_
359
+ while let parentTask = task? . _parentTask {
360
+ if parentTask. _weakified { break }
361
+
362
+ parentTask. resume ( )
363
+ task = parentTask
364
+ }
365
+ }
366
+ configuration. cancel = { [ weak self_] in
367
+ userCancelClosure ? ( )
368
+
369
+ var task : _Task ? = self_
370
+ while let parentTask = task? . _parentTask {
371
+ if parentTask. _weakified { break }
372
+
373
+ parentTask. cancel ( )
374
+ task = parentTask
375
+ }
376
+ }
335
377
336
- parentTask. cancel ( )
337
- task = parentTask
338
378
}
379
+
380
+ }
381
+
382
+ if !paused {
383
+ self . resume ( )
339
384
}
340
385
}
341
386
@@ -672,6 +717,11 @@ public class Task<Progress, Value, Error>: _Task<Error>
672
717
673
718
public override func resume( ) -> Bool
674
719
{
720
+ // always try `_performInitClosure` only once on `resume()`
721
+ // even when to-Resume-transition fails, e.g. already been fulfilled/rejected
722
+ self . _performInitClosure ? ( )
723
+ self . _performInitClosure = nil
724
+
675
725
return self . machine <-! . Resume
676
726
}
677
727
0 commit comments