├── DispatchTimer.playground
├── Contents.swift
├── Sources
│ └── DispatchTimer.swift
├── contents.xcplayground
├── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── hurden.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── timeline.xctimeline
├── DispatchTimer.swift
├── Package.swift
└── README.md
/DispatchTimer.playground/Contents.swift:
--------------------------------------------------------------------------------
1 |
2 | import Foundation
3 | import XCPlayground
4 |
5 | //: __DispatchTimer__ is a GCD-based NSTimer analogue that you can also __pause()__ / __resume()__ and set the finite number of invocations.
6 |
7 | XCPSetExecutionShouldContinueIndefinitely(true)
8 | let timerQueue:dispatch_queue_t = dispatch_queue_create("timerQueue", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_BACKGROUND, 0))
9 |
10 | //: Non-repeating or forever repeating timer
11 |
12 | let singleTimer = DispatchTimer.scheduledTimerWithTimeInterval(milliseconds: 1000, queue: timerQueue, repeats: false) { (timer:DispatchTimer) in
13 |
14 | NSLog("singleTimer: Fired")
15 | }
16 |
17 | sleep(2)
18 | //: Finite timer with multiple invocations(__fireCount__)
19 |
20 | let finiteTimer = DispatchTimer.scheduledTimerWithTimeInterval(milliseconds: 1000, queue: timerQueue, fireCount:10){ (timer:DispatchTimer) in
21 | NSLog("finiteTimer: Fired (remaining:\(timer.remainingFireCount))")
22 | }
23 |
24 | sleep(2)
25 | finiteTimer.pause()
26 |
27 | sleep(1)
28 | finiteTimer.resume()
29 |
30 | sleep(5)
31 | finiteTimer.invalidate()
32 |
33 | //: A bit more customizable factory method
34 | //: You can specify __startOffset__ to let timer start earlier.
35 | //: __tolerance__ specifies an allowable leeway for each invocation scheduling.
36 | //: (Please note the __tolerance__ of 0 does not guarantee precise sceduling. Usually each invocation will have a small deviation)
37 |
38 | let completionHandler = { (timer:DispatchTimer) in NSLog("anotherTimer: Done") }
39 | let anotherTimer = DispatchTimer.scheduledTimerWithTimeInterval(milliseconds: 1000, startOffset: -1000, tolerance: 0, queue: timerQueue, isFinite: true, fireCount: 10, userInfoº: nil, completionHandlerº: completionHandler) { (timer:DispatchTimer) in
40 |
41 | NSLog("anotherTimer: Fired (remaining:\(timer.remainingFireCount))")
42 | }
43 |
44 |
45 | //: Alternatively you can create a timer and start it later.
46 | //: Let's take a look at infinite timer which shows its invocation count
47 | let infiniteTimer = DispatchTimer.timerWithTimeInterval(milliseconds: 1000, queue: timerQueue, repeats: true) { (timer:DispatchTimer) in
48 |
49 | if var userInfo = timer.userInfoº as? UInt {
50 | NSLog("infiniteTimer: Invocation #\(userInfo)")
51 | userInfo++
52 | timer.userInfoº = userInfo
53 | }
54 | }
55 |
56 | infiniteTimer.userInfoº = UInt(0)
57 | infiniteTimer.start()
58 |
59 |
--------------------------------------------------------------------------------
/DispatchTimer.playground/Sources/DispatchTimer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DispatchTimer.swift
3 | // AmbientUPNP
4 | //
5 | // Created by Taras Vozniuk on 7/11/15.
6 | // Copyright (c) 2015 ambientlight. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class DispatchTimer: Equatable {
12 |
13 | public enum Status {
14 | case NotStarted
15 | case Active
16 | case Paused
17 | case Done
18 | case Invalidated
19 | }
20 |
21 | private var _timerSource:dispatch_source_t
22 | private var _isInvalidating:Bool = false
23 | //either startDate or lastFire or lastResume date
24 | private var _lastActiveDateº:NSDate?
25 | private var _elapsedAccumulatedTime: Double = Double(0)
26 |
27 |
28 | //MARK: PROPERTIES
29 |
30 | public private(set) var remainingFireCount:UInt
31 | public private(set) var status:DispatchTimer.Status = .NotStarted
32 | public private(set) var startDateº:NSDate?
33 |
34 | public let queue:dispatch_queue_t
35 | public let isFinite:Bool
36 | public let fireCount:UInt
37 | public let interval:UInt
38 | public let invocationBlock:(timer:DispatchTimer) -> Void
39 |
40 | public var completionHandlerº:((timer:DispatchTimer) -> Void)?
41 | public var userInfoº:Any?
42 |
43 | public var valid:Bool { return (self.status != .Done || self.status != .Invalidated) }
44 | public var started:Bool { return (self.status != .NotStarted) }
45 | public var startAbsoluteTimeº:Double? { return (startDateº != nil) ? self.startDateº!.timeIntervalSince1970 : nil }
46 |
47 |
48 |
49 | //all parameters are in milliseconds
50 | private func _setupTimerSource(timeInterval:UInt, startOffset:UInt, leeway: UInt) {
51 |
52 | dispatch_source_set_timer(_timerSource, dispatch_time(DISPATCH_TIME_NOW, Int64(UInt64(startOffset) * NSEC_PER_MSEC)), UInt64(timeInterval) * NSEC_PER_MSEC, UInt64(leeway) * NSEC_PER_MSEC)
53 | dispatch_source_set_event_handler(_timerSource) {
54 |
55 | self._elapsedAccumulatedTime = 0
56 | self._lastActiveDateº = NSDate()
57 |
58 | self.invocationBlock(timer: self)
59 | if(self.isFinite){
60 |
61 | self.remainingFireCount--
62 | if(self.remainingFireCount == 0){
63 | dispatch_source_cancel(self._timerSource)
64 | }
65 | }
66 | }
67 |
68 | dispatch_source_set_cancel_handler(_timerSource){
69 | if(self._isInvalidating){
70 | self.status = .Invalidated
71 | self._isInvalidating = false
72 | } else {
73 | self.status = .Done
74 | }
75 |
76 | self.completionHandlerº?(timer: self)
77 | }
78 | }
79 |
80 | //MARK:
81 |
82 | public init(milliseconds:UInt, startOffset:Int, tolerance:UInt, queue: dispatch_queue_t, isFinite:Bool, fireCount:UInt, userInfoº:Any?, completionHandlerº:((timer:DispatchTimer) -> Void)?,invocationBlock: (timer:DispatchTimer) -> Void) {
83 |
84 | self.queue = queue
85 |
86 | self.userInfoº = userInfoº
87 | self.isFinite = isFinite
88 | self.fireCount = fireCount;
89 | self.remainingFireCount = self.fireCount
90 |
91 | self.userInfoº = userInfoº
92 | self.completionHandlerº = completionHandlerº
93 | self.invocationBlock = invocationBlock
94 |
95 | self.interval = milliseconds
96 | _timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)
97 |
98 |
99 | let offset:Int = ( (startOffset < 0) && (abs(startOffset) > Int(self.interval)) ) ? -Int(self.interval) : startOffset
100 | _setupTimerSource(self.interval, startOffset: UInt( Int(self.interval) + offset), leeway: tolerance)
101 | }
102 |
103 |
104 | public class func timerWithTimeInterval(milliseconds milliseconds: UInt, queue: dispatch_queue_t, repeats: Bool, invocationBlock: (timer:DispatchTimer) -> Void) -> DispatchTimer {
105 |
106 |
107 | let timer = DispatchTimer(milliseconds: milliseconds, startOffset: 0, tolerance: 0, queue: queue, isFinite: !repeats, fireCount: (repeats) ? 0 : 1, userInfoº: nil, completionHandlerº:nil, invocationBlock: invocationBlock)
108 | return timer
109 | }
110 |
111 | public class func timerWithTimeInterval(milliseconds milliseconds: UInt, queue: dispatch_queue_t, fireCount: UInt, invocationBlock: (timer:DispatchTimer) -> Void) -> DispatchTimer {
112 |
113 | let timer = DispatchTimer(milliseconds: milliseconds, startOffset: 0, tolerance: 0, queue: queue, isFinite: true, fireCount: fireCount, userInfoº: nil, completionHandlerº:nil, invocationBlock: invocationBlock)
114 | return timer
115 | }
116 |
117 |
118 |
119 |
120 | public class func scheduledTimerWithTimeInterval(milliseconds milliseconds: UInt, queue: dispatch_queue_t, repeats: Bool, invocationBlock: (timer:DispatchTimer) -> Void) -> DispatchTimer {
121 |
122 | let timer = DispatchTimer(milliseconds: milliseconds, startOffset: 0, tolerance: 0, queue: queue, isFinite: !repeats, fireCount: (repeats) ? 0 : 1, userInfoº: nil, completionHandlerº:nil, invocationBlock: invocationBlock)
123 | timer.start()
124 | return timer
125 | }
126 |
127 | public class func scheduledTimerWithTimeInterval(milliseconds milliseconds: UInt, queue: dispatch_queue_t, fireCount: UInt, invocationBlock: (timer:DispatchTimer) -> Void) -> DispatchTimer {
128 |
129 | let timer = DispatchTimer(milliseconds: milliseconds, startOffset: 0, tolerance: 0, queue: queue, isFinite: true, fireCount: fireCount, userInfoº: nil, completionHandlerº:nil, invocationBlock: invocationBlock)
130 | timer.start()
131 | return timer
132 | }
133 |
134 | public class func scheduledTimerWithTimeInterval(milliseconds milliseconds:UInt, startOffset:Int, tolerance:UInt, queue: dispatch_queue_t, isFinite:Bool, fireCount:UInt, userInfoº:Any?, completionHandlerº:((timer:DispatchTimer) -> Void)?, invocationBlock: (timer:DispatchTimer) -> Void) -> DispatchTimer {
135 |
136 | let timer = DispatchTimer(milliseconds: milliseconds, startOffset: startOffset, tolerance: tolerance, queue: queue, isFinite: isFinite, fireCount: fireCount, userInfoº: userInfoº, completionHandlerº:completionHandlerº, invocationBlock: invocationBlock)
137 | timer.start()
138 | return timer
139 | }
140 |
141 | //MARK: METHODS
142 |
143 | public func start(){
144 |
145 | if (!self.started){
146 | dispatch_resume(_timerSource)
147 |
148 | self.startDateº = NSDate()
149 | _lastActiveDateº = self.startDateº
150 | self.status = .Active
151 | }
152 | }
153 |
154 | public func pause(){
155 |
156 | if (self.status == .Active){
157 |
158 | dispatch_source_set_cancel_handler(_timerSource){ }
159 | dispatch_source_cancel(_timerSource)
160 | self.status = .Paused
161 |
162 | let pauseDate = NSDate()
163 |
164 | _elapsedAccumulatedTime += (pauseDate.timeIntervalSince1970 - _lastActiveDateº!.timeIntervalSince1970) * 1000
165 |
166 | //NSLog("%ld milliseconds elapsed", UInt(_elapsedAccumulatedTime))
167 | }
168 | }
169 |
170 | public func resume(){
171 |
172 | if (self.status == .Paused){
173 |
174 | //NSLog("%ld milliseconds left till fire", self.interval - UInt(_elapsedAccumulatedTime))
175 |
176 | _timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)
177 | _setupTimerSource(self.interval, startOffset: self.interval - UInt(_elapsedAccumulatedTime), leeway: 0)
178 | dispatch_resume(_timerSource)
179 |
180 | _lastActiveDateº = NSDate()
181 | self.status = .Active
182 | }
183 | }
184 |
185 | public func invalidate(handlerº:((timer:DispatchTimer)-> Void)? = nil){
186 |
187 | _isInvalidating = true;
188 |
189 | // reassigning completionHandler if has been passed(non-nil)
190 | if let handler = completionHandlerº {
191 | self.completionHandlerº = handler
192 | }
193 |
194 | dispatch_source_cancel(_timerSource)
195 | }
196 | }
197 |
198 | //MARK: Equatable
199 | public func ==(lhs: DispatchTimer, rhs: DispatchTimer) -> Bool {
200 | return (lhs._timerSource === rhs._timerSource)
201 | }
202 |
--------------------------------------------------------------------------------
/DispatchTimer.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/DispatchTimer.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DispatchTimer.playground/playground.xcworkspace/xcuserdata/hurden.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ambientlight/DispatchTimer/029803d599d1190e3c3f263ec99dfe0e1c5ad08f/DispatchTimer.playground/playground.xcworkspace/xcuserdata/hurden.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/DispatchTimer.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/DispatchTimer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DispatchTimer.swift
3 | // AmbientUPNP
4 | //
5 | // Created by Taras Vozniuk on 7/11/15.
6 | // Copyright (c) 2015 ambientlight. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class DispatchTimer: Equatable {
12 |
13 | public enum Status {
14 | case NotStarted
15 | case Active
16 | case Paused
17 | case Done
18 | case Invalidated
19 | }
20 |
21 | private var _timerSource:dispatch_source_t
22 | private var _isInvalidating:Bool = false
23 | //either startDate or lastFire or lastResume date
24 | private var _lastActiveDateº:NSDate?
25 | private var _elapsedAccumulatedTime: Double = Double(0)
26 |
27 |
28 | //MARK: PROPERTIES
29 |
30 | public private(set) var remainingFireCount:UInt
31 | public private(set) var status:DispatchTimer.Status = .NotStarted
32 | public private(set) var startDateº:NSDate?
33 |
34 | public let queue:dispatch_queue_t
35 | public let isFinite:Bool
36 | public let fireCount:UInt
37 | public let interval:UInt
38 | public let invocationBlock:(timer:DispatchTimer) -> Void
39 |
40 | public var completionHandlerº:((timer:DispatchTimer) -> Void)?
41 | public var userInfoº:Any?
42 |
43 | public var valid:Bool { return (self.status != .Done || self.status != .Invalidated) }
44 | public var started:Bool { return (self.status != .NotStarted) }
45 | public var startAbsoluteTimeº:Double? { return (startDateº != nil) ? self.startDateº!.timeIntervalSince1970 : nil }
46 |
47 |
48 |
49 | //all parameters are in milliseconds
50 | private func _setupTimerSource(timeInterval:UInt, startOffset:UInt, leeway: UInt) {
51 |
52 | dispatch_source_set_timer(_timerSource, dispatch_time(DISPATCH_TIME_NOW, Int64(UInt64(startOffset) * NSEC_PER_MSEC)), UInt64(timeInterval) * NSEC_PER_MSEC, UInt64(leeway) * NSEC_PER_MSEC)
53 | dispatch_source_set_event_handler(_timerSource) {
54 |
55 | self._elapsedAccumulatedTime = 0
56 | self._lastActiveDateº = NSDate()
57 |
58 | self.invocationBlock(timer: self)
59 | if(self.isFinite){
60 |
61 | self.remainingFireCount -= 1
62 | if(self.remainingFireCount == 0){
63 | dispatch_source_cancel(self._timerSource)
64 | }
65 | }
66 | }
67 |
68 | dispatch_source_set_cancel_handler(_timerSource){
69 | if(self._isInvalidating){
70 | self.status = .Invalidated
71 | self._isInvalidating = false
72 | } else {
73 | self.status = .Done
74 | }
75 |
76 | self.completionHandlerº?(timer: self)
77 | }
78 | }
79 |
80 | //MARK:
81 |
82 | public init(milliseconds:UInt, startOffset:Int, tolerance:UInt, queue: dispatch_queue_t, isFinite:Bool, fireCount:UInt, userInfoº:Any?, completionHandlerº:((timer:DispatchTimer) -> Void)?,invocationBlock: (timer:DispatchTimer) -> Void) {
83 |
84 | self.queue = queue
85 |
86 | self.userInfoº = userInfoº
87 | self.isFinite = isFinite
88 | self.fireCount = fireCount;
89 | self.remainingFireCount = self.fireCount
90 |
91 | self.userInfoº = userInfoº
92 | self.completionHandlerº = completionHandlerº
93 | self.invocationBlock = invocationBlock
94 |
95 | self.interval = milliseconds
96 | _timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)
97 |
98 |
99 | let offset:Int = ( (startOffset < 0) && (abs(startOffset) > Int(self.interval)) ) ? -Int(self.interval) : startOffset
100 | _setupTimerSource(self.interval, startOffset: UInt( Int(self.interval) + offset), leeway: tolerance)
101 | }
102 |
103 |
104 | public class func timerWithTimeInterval(milliseconds milliseconds: UInt, queue: dispatch_queue_t, repeats: Bool, invocationBlock: (timer:DispatchTimer) -> Void) -> DispatchTimer {
105 |
106 |
107 | let timer = DispatchTimer(milliseconds: milliseconds, startOffset: 0, tolerance: 0, queue: queue, isFinite: !repeats, fireCount: (repeats) ? 0 : 1, userInfoº: nil, completionHandlerº:nil, invocationBlock: invocationBlock)
108 | return timer
109 | }
110 |
111 | public class func timerWithTimeInterval(milliseconds milliseconds: UInt, queue: dispatch_queue_t, fireCount: UInt, invocationBlock: (timer:DispatchTimer) -> Void) -> DispatchTimer {
112 |
113 | let timer = DispatchTimer(milliseconds: milliseconds, startOffset: 0, tolerance: 0, queue: queue, isFinite: true, fireCount: fireCount, userInfoº: nil, completionHandlerº:nil, invocationBlock: invocationBlock)
114 | return timer
115 | }
116 |
117 |
118 |
119 |
120 | public class func scheduledTimerWithTimeInterval(milliseconds milliseconds: UInt, queue: dispatch_queue_t, repeats: Bool, invocationBlock: (timer:DispatchTimer) -> Void) -> DispatchTimer {
121 |
122 | let timer = DispatchTimer(milliseconds: milliseconds, startOffset: 0, tolerance: 0, queue: queue, isFinite: !repeats, fireCount: (repeats) ? 0 : 1, userInfoº: nil, completionHandlerº:nil, invocationBlock: invocationBlock)
123 | timer.start()
124 | return timer
125 | }
126 |
127 | public class func scheduledTimerWithTimeInterval(milliseconds milliseconds: UInt, queue: dispatch_queue_t, fireCount: UInt, invocationBlock: (timer:DispatchTimer) -> Void) -> DispatchTimer {
128 |
129 | let timer = DispatchTimer(milliseconds: milliseconds, startOffset: 0, tolerance: 0, queue: queue, isFinite: true, fireCount: fireCount, userInfoº: nil, completionHandlerº:nil, invocationBlock: invocationBlock)
130 | timer.start()
131 | return timer
132 | }
133 |
134 | public class func scheduledTimerWithTimeInterval(milliseconds milliseconds:UInt, startOffset:Int, tolerance:UInt, queue: dispatch_queue_t, isFinite:Bool, fireCount:UInt, userInfoº:Any?, completionHandlerº:((timer:DispatchTimer) -> Void)?, invocationBlock: (timer:DispatchTimer) -> Void) -> DispatchTimer {
135 |
136 | let timer = DispatchTimer(milliseconds: milliseconds, startOffset: startOffset, tolerance: tolerance, queue: queue, isFinite: isFinite, fireCount: fireCount, userInfoº: userInfoº, completionHandlerº:completionHandlerº, invocationBlock: invocationBlock)
137 | timer.start()
138 | return timer
139 | }
140 |
141 | //MARK: METHODS
142 |
143 | public func start(){
144 |
145 | if (!self.started){
146 | dispatch_resume(_timerSource)
147 |
148 | self.startDateº = NSDate()
149 | _lastActiveDateº = self.startDateº
150 | self.status = .Active
151 | }
152 | }
153 |
154 | public func pause(){
155 |
156 | if (self.status == .Active){
157 |
158 | dispatch_source_set_cancel_handler(_timerSource){ }
159 | dispatch_source_cancel(_timerSource)
160 | self.status = .Paused
161 |
162 | let pauseDate = NSDate()
163 |
164 | _elapsedAccumulatedTime += (pauseDate.timeIntervalSince1970 - _lastActiveDateº!.timeIntervalSince1970) * 1000
165 |
166 | //NSLog("%ld milliseconds elapsed", UInt(_elapsedAccumulatedTime))
167 | }
168 | }
169 |
170 | public func resume(){
171 |
172 | if (self.status == .Paused){
173 |
174 | //NSLog("%ld milliseconds left till fire", self.interval - UInt(_elapsedAccumulatedTime))
175 |
176 | _timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)
177 | _setupTimerSource(self.interval, startOffset: self.interval - UInt(_elapsedAccumulatedTime), leeway: 0)
178 | dispatch_resume(_timerSource)
179 |
180 | _lastActiveDateº = NSDate()
181 | self.status = .Active
182 | }
183 | }
184 |
185 | public func invalidate(handlerº:((timer:DispatchTimer)-> Void)? = nil){
186 |
187 | _isInvalidating = true;
188 |
189 | // reassigning completionHandler if has been passed(non-nil)
190 | if let handler = completionHandlerº {
191 | self.completionHandlerº = handler
192 | }
193 |
194 | dispatch_source_cancel(_timerSource)
195 | }
196 | }
197 |
198 | //MARK: Equatable
199 | public func ==(lhs: DispatchTimer, rhs: DispatchTimer) -> Bool {
200 | return (lhs._timerSource === rhs._timerSource)
201 | }
202 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | import PackageDescription
2 |
3 | let package = Package(name:"DispatchTimer")
4 |
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ##DispatchTimer
2 | __DispatchTimer__ is a GCD-based NSTimer analogue that you can also __pause__/__resume__ and set a finite number of invocations.
3 |
4 |
5 |
6 | ##Examples
7 | Please take a look at __DispatchTimer.playground__.
8 |
9 | ####Non-repeating or Infinite timer
10 |
11 | ```swift
12 | let timerQueue:dispatch_queue_t = dispatch_queue_create("timerQueue", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_BACKGROUND, 0))
13 |
14 | let singleTimer = DispatchTimer.scheduledTimerWithTimeInterval(milliseconds: 1000, queue: timerQueue, repeats: false) { (timer:DispatchTimer) in
15 | NSLog("singleTimer: Fired")
16 | }
17 | ```
18 |
19 | ####Finite timer(multiple # of invocations)
20 | ```swift
21 | let timerQueue:dispatch_queue_t = dispatch_queue_create("timerQueue", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_BACKGROUND, 0))
22 |
23 | let finiteTimer = DispatchTimer.scheduledTimerWithTimeInterval(milliseconds: 1000, queue: timerQueue, fireCount:10){ (timer:DispatchTimer) in
24 | NSLog("finiteTimer: Fired (remaining:\(timer.remainingFireCount))")
25 | }
26 |
27 | sleep(2)
28 | finiteTimer.pause()
29 |
30 | sleep(1)
31 | finiteTimer.resume()
32 |
33 | sleep(5)
34 | finiteTimer.invalidate()
35 |
36 | ```
37 |
38 | ####More examples
39 | In a bit longer factory method you can specify __startOffset__ to let timer start earlier.
40 | __tolerance__ specifies an allowable leeway for each invocation scheduling.
41 | (Please note the __tolerance__ of 0 does not guarantee precise sceduling. Usually each invocation will have a small deviation)
42 |
43 | ```swift
44 | let timerQueue:dispatch_queue_t = dispatch_queue_create("timerQueue",
45 |
46 | let completionHandler = { (timer:DispatchTimer) in NSLog("anotherTimer: Done") }
47 | let anotherTimer = DispatchTimer.scheduledTimerWithTimeInterval(milliseconds: 1000, startOffset: -1000, tolerance: 0, queue: timerQueue, isFinite: true, fireCount: 10, userInfoº: nil, completionHandlerº: completionHandler) { (timer:DispatchTimer) in
48 | NSLog("anotherTimer: Fired (remaining:\(timer.remainingFireCount))")
49 | }
50 | ```
51 |
52 | Alternatively you can also create a timer and start it later.
53 | Lets take a look at the infinite timer which shows its invocation count
54 |
55 | ```swift
56 | let timerQueue:dispatch_queue_t = dispatch_queue_create("timerQueue",
57 |
58 | let infiniteTimer = DispatchTimer.timerWithTimeInterval(milliseconds: 1000, queue: timerQueue, repeats: true) { (timer:DispatchTimer) in
59 | if var userInfo = timer.userInfoº as? UInt {
60 | NSLog("infiniteTimer: Invocation #\(userInfo)")
61 | userInfo++
62 | timer.userInfoº = userInfo
63 | }
64 | }
65 |
66 | infiniteTimer.userInfoº = UInt(0)
67 | infiniteTimer.start()
68 | ```
69 | ##Requirement
70 | * Swift 2.0 (Xcode 7+)
71 | * iOS 7+
--------------------------------------------------------------------------------