Files
ShadowsocksX-NG/Pods/RxSwift/RxSwift/Schedulers/Internal/DispatchQueueConfiguration.swift
2017-03-20 21:26:25 +08:00

105 lines
3.4 KiB
Swift

//
// DispatchQueueConfiguration.swift
// RxSwift
//
// Created by Krunoslav Zaher on 7/23/16.
// Copyright © 2016 Krunoslav Zaher. All rights reserved.
//
import Dispatch
import struct Foundation.TimeInterval
struct DispatchQueueConfiguration {
let queue: DispatchQueue
let leeway: DispatchTimeInterval
}
private func dispatchInterval(_ interval: Foundation.TimeInterval) -> DispatchTimeInterval {
precondition(interval >= 0.0)
// TODO: Replace 1000 with something that actually works
// NSEC_PER_MSEC returns 1000000
return DispatchTimeInterval.milliseconds(Int(interval * 1000.0))
}
extension DispatchQueueConfiguration {
func schedule<StateType>(_ state: StateType, action: @escaping (StateType) -> Disposable) -> Disposable {
let cancel = SingleAssignmentDisposable()
queue.async {
if cancel.isDisposed {
return
}
cancel.setDisposable(action(state))
}
return cancel
}
func scheduleRelative<StateType>(_ state: StateType, dueTime: Foundation.TimeInterval, action: @escaping (StateType) -> Disposable) -> Disposable {
let deadline = DispatchTime.now() + dispatchInterval(dueTime)
let compositeDisposable = CompositeDisposable()
let timer = DispatchSource.makeTimerSource(queue: queue)
timer.scheduleOneshot(deadline: deadline)
// TODO:
// This looks horrible, and yes, it is.
// It looks like Apple has made a conceputal change here, and I'm unsure why.
// Need more info on this.
// It looks like just setting timer to fire and not holding a reference to it
// until deadline causes timer cancellation.
var timerReference: DispatchSourceTimer? = timer
let cancelTimer = Disposables.create {
timerReference?.cancel()
timerReference = nil
}
timer.setEventHandler(handler: {
if compositeDisposable.isDisposed {
return
}
_ = compositeDisposable.insert(action(state))
cancelTimer.dispose()
})
timer.resume()
_ = compositeDisposable.insert(cancelTimer)
return compositeDisposable
}
func schedulePeriodic<StateType>(_ state: StateType, startAfter: TimeInterval, period: TimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {
let initial = DispatchTime.now() + dispatchInterval(startAfter)
var timerState = state
let timer = DispatchSource.makeTimerSource(queue: queue)
timer.scheduleRepeating(deadline: initial, interval: dispatchInterval(period), leeway: leeway)
// TODO:
// This looks horrible, and yes, it is.
// It looks like Apple has made a conceputal change here, and I'm unsure why.
// Need more info on this.
// It looks like just setting timer to fire and not holding a reference to it
// until deadline causes timer cancellation.
var timerReference: DispatchSourceTimer? = timer
let cancelTimer = Disposables.create {
timerReference?.cancel()
timerReference = nil
}
timer.setEventHandler(handler: {
if cancelTimer.isDisposed {
return
}
timerState = action(timerState)
})
timer.resume()
return cancelTimer
}
}