Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift 2.3 support #13

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 17 additions & 15 deletions DispatchGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,49 @@
import CoreGraphics
import Dispatch

public typealias Group = DispatchGroup

public class DispatchGroup {
open class DispatcherGroup {

public init (_ tasks: Int = 0) {
for _ in 0..<tasks { ++self }
}

public private(set) var tasks = 0
open fileprivate(set) var tasks = 0

public let dispatch_group = dispatch_group_create()
open let dispatch_group = DispatchGroup()

public func done (callback: Void -> Void) {
dispatch_group_notify(dispatch_group, gcd.current.dispatch_queue, callback)
open func done (_ callback: @escaping (Void) -> Void) {
guard let current = gcd.current else {
return
}

dispatch_group.notify(queue: current.dispatch_queue, execute: callback)
}

public func wait (delay: CGFloat, _ callback: Void -> Void) {
dispatch_group_wait(dispatch_group, dispatch_time(DISPATCH_TIME_NOW, Int64(delay * CGFloat(NSEC_PER_SEC))))
open func wait (_ delay: CGFloat, _ callback: (Void) -> Void) {
let _ = dispatch_group.wait(timeout: DispatchTime.now() + Double(Int64(delay * CGFloat(NSEC_PER_SEC))) / Double(NSEC_PER_SEC))
}

deinit { assert(tasks == 0, "A DispatchGroup cannot be deallocated when tasks is greater than zero!") }
}

public prefix func ++ (group: DispatchGroup) {
public prefix func ++ (group: DispatcherGroup) {
objc_sync_enter(group)
group.tasks += 1
dispatch_group_enter(group.dispatch_group)
group.dispatch_group.enter()
objc_sync_exit(group)
}

public prefix func -- (group: DispatchGroup) {
public prefix func -- (group: DispatcherGroup) {
objc_sync_enter(group)
group.tasks -= 1
dispatch_group_leave(group.dispatch_group)
group.dispatch_group.leave()
objc_sync_exit(group)
}

public postfix func ++ (group: DispatchGroup) {
public postfix func ++ (group: DispatcherGroup) {
++group
}

public postfix func -- (group: DispatchGroup) {
public postfix func -- (group: DispatcherGroup) {
--group
}
64 changes: 38 additions & 26 deletions DispatchQueue.swift
Original file line number Diff line number Diff line change
@@ -1,70 +1,82 @@

import Foundation

public typealias Queue = DispatchQueue

public class DispatchQueue {
open class DispatcherQueue {

private static let Label = "com.mobilenatives.dispatcher"

// MARK: Public

public let isConcurrent: Bool
open let isConcurrent: Bool

public var isCurrent: Bool { return dispatch_get_specific(&kCurrentQueue) == getMutablePointer(self) }
open var isCurrent: Bool {
return DispatchQueue.getSpecific(key: kCurrentQueue) == getMutablePointer(self)
}

public func async (callback: Void -> Void) {
dispatch_async(dispatch_queue) { callback() }
open func async (_ callback: @escaping (Void) -> Void) {
dispatch_queue.async(execute: callback)
}

public func sync (callback: Void -> Void) {
open func sync (_ callback: (Void) -> Void) {
if isCurrent { callback(); return } // prevent deadlocks!
dispatch_sync(dispatch_queue) { callback() }
dispatch_queue.sync(execute: callback)
}

public func async <T> (callback: T -> Void) -> T -> Void {
open func async <T> (_ callback: @escaping (T) -> Void) -> (T) -> Void {
return { [weak self] value in
if self == nil { return }
self!.async { callback(value) }
guard let strongSelf = self else { return }
strongSelf.async { callback(value) }
}
}

public func sync <T> (callback: T -> Void) -> T -> Void {
open func sync <T> (_ callback: @escaping (T) -> Void) -> (T) -> Void {
return { [weak self] value in
if self == nil { return }
self!.sync { callback(value) }
guard let strongSelf = self else { return }
strongSelf.sync { callback(value) }
}
}

public let dispatch_queue: dispatch_queue_t
open let dispatch_queue: DispatchQueue



// MARK: Internal

init (_ queue: dispatch_queue_t) {
init (queue: DispatchQueue) {
isConcurrent = false
dispatch_queue = queue
remember()
}
init (_ priority: dispatch_queue_priority_t) {

init (qos: DispatchQoS.QoSClass) {
isConcurrent = true
dispatch_queue = dispatch_get_global_queue(priority, 0)
dispatch_queue = DispatchQueue.global(qos: qos)
remember()
}

init (_ concurrent: Bool) {
init (concurrent: Bool) {
isConcurrent = concurrent
dispatch_queue = dispatch_queue_create(nil, isConcurrent ? DISPATCH_QUEUE_CONCURRENT : DISPATCH_QUEUE_SERIAL)

// https://bugs.swift.org/browse/SR-1859
if #available(iOS 10.0, *) {
dispatch_queue = DispatchQueue(label: DispatcherQueue.Label, attributes: isConcurrent ? [DispatchQueue.Attributes.concurrent, DispatchQueue.Attributes.initiallyInactive] : [DispatchQueue.Attributes.initiallyInactive])
} else {
dispatch_queue = isConcurrent ? DispatchQueue(label: DispatcherQueue.Label, attributes: [DispatchQueue.Attributes.concurrent]) : DispatchQueue(label: DispatcherQueue.Label)
}
remember()
}

func remember () {
dispatch_queue_set_specific(dispatch_queue, &kCurrentQueue, getMutablePointer(self), nil)
guard let mutablePointer = getMutablePointer(self) else {
return
}

dispatch_queue.setSpecific(key: kCurrentQueue, value: mutablePointer)
}
}

var kCurrentQueue = 0
var kCurrentQueue = DispatchSpecificKey<UnsafeMutableRawPointer>()

func getMutablePointer (object: AnyObject) -> UnsafeMutablePointer<Void> {
return UnsafeMutablePointer<Void>(bitPattern: Int(ObjectIdentifier(object).uintValue))
func getMutablePointer (_ object: AnyObject) -> UnsafeMutableRawPointer? {
return UnsafeMutableRawPointer(bitPattern: Int(bitPattern: ObjectIdentifier(object)))
}
52 changes: 29 additions & 23 deletions DispatchTimer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@
import Foundation
import UIKit

public typealias Timer = DispatchTimer
open class DispatcherTimer {

public class DispatchTimer {

public convenience init (_ delay: CGFloat, _ callback: Void -> Void) {
public convenience init (_ delay: CGFloat, _ callback: @escaping (Void) -> Void) {
self.init(delay, 0, callback)
}

public init (_ delay: CGFloat, _ tolerance: CGFloat, _ callback: Void -> Void) {
public init (_ delay: CGFloat, _ tolerance: CGFloat, _ callback: @escaping (Void) -> Void) {
self.callback = callback
self.tolerance = tolerance

Expand All @@ -20,57 +18,65 @@ public class DispatchTimer {
}

self.callbackQueue = gcd.current
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue.dispatch_queue)
self.timer = DispatchSource.makeTimerSource(flags: DispatchSource.TimerFlags(rawValue: 0), queue: queue.dispatch_queue)

if !gcd.main.isCurrent { dispatch_set_target_queue(queue.dispatch_queue, gcd.current.dispatch_queue) }
if !gcd.main.isCurrent {
if let dispatch_queue = gcd.current?.dispatch_queue {
queue.dispatch_queue.setTarget(queue: dispatch_queue)
}
}

let delay_ns = delay * CGFloat(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay_ns))
dispatch_source_set_timer(timer, time, UInt64(delay_ns), UInt64(tolerance * CGFloat(NSEC_PER_SEC)))
dispatch_source_set_event_handler(timer) { [weak self] in let _ = self?.fire() }
dispatch_resume(timer)
let time = DispatchTime.now() + Double(delay)

let interval = DispatchTimeInterval.nanoseconds(Int(delay_ns))
let leeway = DispatchTimeInterval.nanoseconds(Int(UInt64(tolerance * CGFloat(NSEC_PER_SEC))))

timer?.scheduleRepeating(deadline: time, interval: interval, leeway: leeway)
timer?.setEventHandler { [weak self] in let _ = self?.fire() }
timer?.resume()
}

// MARK: Read-only

public let tolerance: CGFloat
open let tolerance: CGFloat

public let callback: Void -> Void
open let callback: (Void) -> Void

// MARK: Instance methods

public func doRepeat (times: UInt! = nil) {
open func doRepeat (_ times: UInt! = nil) {
isRepeating = true
repeatsLeft = times != nil ? Int(times) : -1
}

public func autorelease () {
open func autorelease () {
isAutoReleased = true
autoReleasedTimers[ObjectIdentifier(self)] = self
}

public func fire () {
open func fire () {
if OSAtomicAnd32OrigBarrier(1, &invalidated) == 1 { return }
callbackQueue.sync(callback)
callbackQueue?.sync(callback)
if isRepeating && repeatsLeft > 0 {
repeatsLeft -= 1
}
if !isRepeating || repeatsLeft == 0 { stop() }
}

public func stop () {
open func stop () {
if OSAtomicTestAndSetBarrier(7, &invalidated) { return }
queue.sync({dispatch_source_cancel(self.timer)})
queue.sync({self.timer?.cancel()})
if isAutoReleased { autoReleasedTimers[ObjectIdentifier(self)] = nil }
}

// MARK: Internal

var timer: dispatch_source_t!
var timer: DispatchSourceTimer?

let queue: DispatchQueue = gcd.serial()
let queue: DispatcherQueue = gcd.serial()

var callbackQueue: DispatchQueue!
var callbackQueue: DispatcherQueue?

var invalidated: UInt32 = 0

Expand All @@ -85,4 +91,4 @@ public class DispatchTimer {
}
}

var autoReleasedTimers = [ObjectIdentifier:Timer]()
var autoReleasedTimers = [ObjectIdentifier:DispatcherTimer]()
30 changes: 17 additions & 13 deletions Dispatcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,31 @@ import Dispatch

public let gcd = Dispatcher()

public class Dispatcher : DispatchQueue {
public class Dispatcher : DispatcherQueue {

public var current: DispatchQueue {
return Unmanaged<DispatchQueue>.fromOpaque(COpaquePointer(dispatch_get_specific(&kCurrentQueue))).takeUnretainedValue()
public var current: DispatcherQueue? {
guard let unsafeRawPoiner = DispatchQueue.getSpecific(key: kCurrentQueue) else {
return nil
}

return Unmanaged<DispatcherQueue>.fromOpaque(unsafeRawPoiner).takeUnretainedValue()
}

public let main = DispatchQueue(dispatch_get_main_queue())
public let main = DispatcherQueue(queue: DispatchQueue.main)

public let high = DispatchQueue(DISPATCH_QUEUE_PRIORITY_HIGH)
public let high = DispatcherQueue(qos: .userInitiated)

public let low = DispatchQueue(DISPATCH_QUEUE_PRIORITY_LOW)
public let low = DispatcherQueue(qos: .utility)

public let background = DispatchQueue(DISPATCH_QUEUE_PRIORITY_BACKGROUND)
public let background = DispatcherQueue(qos: .background)

public func serial () -> DispatchQueue {
return DispatchQueue(false)
public func serial () -> DispatcherQueue {
return DispatcherQueue(concurrent: false)
}

public func concurrent () -> DispatchQueue {
return DispatchQueue(true)
public func concurrent () -> DispatcherQueue {
return DispatcherQueue(concurrent: true)
}

init () { super.init(DISPATCH_QUEUE_PRIORITY_DEFAULT) }
}
init () { super.init(qos: .default) }
}
Loading