Skip to content
This repository has been archived by the owner on Feb 28, 2020. It is now read-only.

Commit

Permalink
Merge branch 'release/2.1.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
vmartinelli committed Feb 3, 2016
2 parents f91a52c + 79a74be commit ef93877
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 141 deletions.
2 changes: 1 addition & 1 deletion AlecrimAsyncKit.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|

s.name = "AlecrimAsyncKit"
s.version = "2.1"
s.version = "2.1.1"
s.summary = "Bringing async and await to Swift world with some flavouring."
s.homepage = "https://github.com/Alecrim/AlecrimAsyncKit"

Expand Down
4 changes: 2 additions & 2 deletions Source/AlecrimAsyncKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 177;
CURRENT_PROJECT_VERSION = 197;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
Expand All @@ -401,7 +401,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 177;
CURRENT_PROJECT_VERSION = 197;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,58 +10,71 @@ import Foundation

#if os(iOS)


public final class NetworkActivityIndicatorTaskObserver: TaskObserver {

private static var activitySpinLock = OS_SPINLOCK_INIT
private static var activity: Int = 0

public static var delay: NSTimeInterval = 0.5
private static var _activitySpinLock = OS_SPINLOCK_INIT
private static var _activity: Int = 0

private let application: UIApplication
public static var delay: NSTimeInterval = 0.25

private unowned let application: UIApplication

private init(application: UIApplication) {
self.application = application
super.init()

self.taskDidStart { _ in
self.incrementActivity()
}

self.taskDidFinish { _ in
self.decrementActivity()
self
.taskDidStart { _ in
self.incrementActivity()
}
.taskDidFinish { _ in
self.decrementActivity()
}
}

private func showOrHideActivityIndicatorAfterDelay() {
let when = dispatch_time(DISPATCH_TIME_NOW, Int64(self.dynamicType.delay * Double(NSEC_PER_SEC)))
dispatch_after(when, dispatch_get_main_queue()) {
withUnsafeMutablePointer(&self.dynamicType.activitySpinLock, OSSpinLockLock)
self.application.networkActivityIndicatorVisible = (self.dynamicType.activity > 0)
withUnsafeMutablePointer(&self.dynamicType.activitySpinLock, OSSpinLockUnlock)
private func incrementActivity() {
do {
withUnsafeMutablePointer(&self.dynamicType._activitySpinLock, OSSpinLockLock)
defer { withUnsafeMutablePointer(&self.dynamicType._activitySpinLock, OSSpinLockUnlock) }

self.dynamicType._activity++
}

self.showOrHideActivityIndicatorAfterDelay()
}


public func incrementActivity() {
withUnsafeMutablePointer(&self.dynamicType.activitySpinLock, OSSpinLockLock)
self.dynamicType.activity++
withUnsafeMutablePointer(&self.dynamicType.activitySpinLock, OSSpinLockUnlock)
private func decrementActivity() {
do {
withUnsafeMutablePointer(&self.dynamicType._activitySpinLock, OSSpinLockLock)
defer { withUnsafeMutablePointer(&self.dynamicType._activitySpinLock, OSSpinLockUnlock) }

self.dynamicType._activity--

#if DEBUG
if self.dynamicType._activity < 0 {
print("Something is wrong -> activity count:", self.dynamicType._activity)
}
#endif
}

self.showOrHideActivityIndicatorAfterDelay()
}

public func decrementActivity() {
withUnsafeMutablePointer(&self.dynamicType.activitySpinLock, OSSpinLockLock)
self.dynamicType.activity--
private func showOrHideActivityIndicatorAfterDelay() {
let when = dispatch_time(DISPATCH_TIME_NOW, Int64(self.dynamicType.delay * Double(NSEC_PER_SEC)))

if self.dynamicType.activity < 0 {
print("Something is wrong -> activity count:", self.dynamicType.activity)
dispatch_after(when, dispatch_get_main_queue()) {
withUnsafeMutablePointer(&self.dynamicType._activitySpinLock, OSSpinLockLock)
defer { withUnsafeMutablePointer(&self.dynamicType._activitySpinLock, OSSpinLockUnlock) }

let visible = (self.dynamicType._activity > 0)
if visible && !self.application.networkActivityIndicatorVisible {
self.application.networkActivityIndicatorVisible = true
}
else if !visible && self.application.networkActivityIndicatorVisible {
self.application.networkActivityIndicatorVisible = false
}
}

withUnsafeMutablePointer(&self.dynamicType.activitySpinLock, OSSpinLockUnlock)

self.showOrHideActivityIndicatorAfterDelay()
}

}
Expand All @@ -80,8 +93,25 @@ import Foundation

extension UIApplication {

private struct AssociatedKeys {
private static var networkActivity = "networkActivity"
}

public var networkActivity: NetworkActivityIndicatorTaskObserver {
if let value = objc_getAssociatedObject(self, &AssociatedKeys.networkActivity) as? NetworkActivityIndicatorTaskObserver {
return value
}
else {
let value = NetworkActivityIndicatorTaskObserver(application: self)
objc_setAssociatedObject(self, &AssociatedKeys.networkActivity, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC )

return value
}
}

@available(*, unavailable, renamed="networkActivity")
public func networkActivityIndicatorTaskObserver() -> NetworkActivityIndicatorTaskObserver {
return NetworkActivityIndicatorTaskObserver(application: self)
fatalError()
}

}
Expand Down
45 changes: 21 additions & 24 deletions Source/AlecrimAsyncKit/Core/AsyncAwait.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,21 @@ public typealias TaskPriority = NSOperationQueuePriority
// MARK: - async

@warn_unused_result
public func async<V>(queue: NSOperationQueue = _defaultTaskQueue, qualityOfService: NSQualityOfService? = nil, observers: [TaskObserver]? = nil, closure: () -> V) -> NonFailableTask<V> {
return asyncEx(queue, qualityOfService: qualityOfService, observers: observers) { task in
public func async<V>(queue: NSOperationQueue = _defaultTaskQueue, qualityOfService: NSQualityOfService? = nil, taskPriority: TaskPriority? = nil, observers: [TaskObserver]? = nil, closure: () -> V) -> NonFailableTask<V> {
return taskWithQueue(queue, qualityOfService: qualityOfService, taskPriority: taskPriority, conditions: nil, observers: observers, asynchronous: false) { task in
let value = closure()
task.finishWithValue(value)
}
}

@warn_unused_result
public func async<V>(queue: NSOperationQueue = _defaultTaskQueue, qualityOfService: NSQualityOfService? = nil, condition: TaskCondition, observers: [TaskObserver]? = nil, closure: () throws -> V) -> Task<V> {
return async(queue, qualityOfService: qualityOfService, conditions: [condition], observers: observers, closure: closure)
public func async<V>(queue: NSOperationQueue = _defaultTaskQueue, qualityOfService: NSQualityOfService? = nil, taskPriority: TaskPriority? = nil, condition: TaskCondition, observers: [TaskObserver]? = nil, closure: () throws -> V) -> Task<V> {
return async(queue, qualityOfService: qualityOfService, conditions: [condition], taskPriority: taskPriority, observers: observers, closure: closure)
}

@warn_unused_result
public func async<V>(queue: NSOperationQueue = _defaultTaskQueue, qualityOfService: NSQualityOfService? = nil, conditions: [TaskCondition]? = nil, observers: [TaskObserver]? = nil, closure: () throws -> V) -> Task<V> {
return asyncEx(queue, qualityOfService: qualityOfService, observers: observers) { task in
public func async<V>(queue: NSOperationQueue = _defaultTaskQueue, qualityOfService: NSQualityOfService? = nil, taskPriority: TaskPriority? = nil, conditions: [TaskCondition]? = nil, observers: [TaskObserver]? = nil, closure: () throws -> V) -> Task<V> {
return taskWithQueue(queue, qualityOfService: qualityOfService, taskPriority: taskPriority, conditions: conditions, observers: observers, asynchronous: false) { task in
do {
let value = try closure()
task.finishWithValue(value)
Expand All @@ -53,7 +53,7 @@ public func async<V>(queue: NSOperationQueue = _defaultTaskQueue, qualityOfServi

@warn_unused_result
public func asyncEx<V>(queue: NSOperationQueue = _defaultTaskQueue, qualityOfService: NSQualityOfService? = nil, taskPriority: TaskPriority? = nil, observers: [TaskObserver]? = nil, closure: (NonFailableTask<V>) -> Void) -> NonFailableTask<V> {
return taskWithQueue(queue, qualityOfService: qualityOfService, taskPriority: taskPriority, conditions: nil, observers: observers, closure: closure)
return taskWithQueue(queue, qualityOfService: qualityOfService, taskPriority: taskPriority, conditions: nil, observers: observers, asynchronous: true, closure: closure)
}

@warn_unused_result
Expand All @@ -64,7 +64,7 @@ public func asyncEx<V>(queue: NSOperationQueue = _defaultTaskQueue, qualityOfSer

@warn_unused_result
public func asyncEx<V>(queue: NSOperationQueue = _defaultTaskQueue, qualityOfService: NSQualityOfService? = nil, taskPriority: TaskPriority? = nil, conditions: [TaskCondition]? = nil, observers: [TaskObserver]? = nil, closure: (Task<V>) -> Void) -> Task<V> {
return taskWithQueue(queue, qualityOfService: qualityOfService, taskPriority: taskPriority, conditions: conditions, observers: observers, closure: closure)
return taskWithQueue(queue, qualityOfService: qualityOfService, taskPriority: taskPriority, conditions: conditions, observers: observers, asynchronous: true, closure: closure)
}


Expand Down Expand Up @@ -98,30 +98,27 @@ public func await<V>(task: Task<V>) throws -> V {

// MARK: -

private func taskWithQueue<T: InitializableTaskType>(queue: NSOperationQueue, qualityOfService: NSQualityOfService?, taskPriority: TaskPriority?, conditions: [TaskCondition]?, observers: [TaskObserver]?, closure: (T) -> Void) -> T {
private func taskWithQueue<T: InitializableTaskType>(queue: NSOperationQueue, qualityOfService: NSQualityOfService?, taskPriority: TaskPriority?, conditions: [TaskCondition]?, observers: [TaskObserver]?, asynchronous: Bool, closure: (T) -> Void) -> T {
assert(queue.maxConcurrentOperationCount == NSOperationQueueDefaultMaxConcurrentOperationCount || queue.maxConcurrentOperationCount > 1, "Task `queue` cannot be the main queue nor a serial queue.")

//
let task = T(conditions: conditions, observers: observers, closure: closure)
let task = T(conditions: conditions, observers: observers, asynchronous: asynchronous, closure: closure)
let operation = task as! TaskOperation

//
if let operation = task as? TaskOperation {
if let qualityOfService = qualityOfService {
operation.qualityOfService = qualityOfService
}

if let taskPriority = taskPriority {
operation.queuePriority = taskPriority
}

//
operation.willEnqueue()
queue.addOperation(operation)
if let qualityOfService = qualityOfService {
operation.qualityOfService = qualityOfService
}
else {
fatalError()

if let taskPriority = taskPriority {
operation.queuePriority = taskPriority
}

//
operation.willEnqueue()
queue.addOperation(operation)

//
return task
}

68 changes: 36 additions & 32 deletions Source/AlecrimAsyncKit/Core/MutuallyExclusiveTaskCondition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,32 @@

import Foundation

private final class Semaphore {
private let dispatch_semaphore: dispatch_semaphore_t
private var count: Int

private init(dispatch_semaphore: dispatch_semaphore_t, count: Int) {
self.dispatch_semaphore = dispatch_semaphore
self.count = count
}
}

/// A condition for describing kinds of operations that may not execute concurrently.
public final class MutuallyExclusiveTaskCondition: TaskCondition {

/// An enumeration with the default categories used by the condition.
///
/// - Alert: The category that represents a potential modal alert to the user.
public enum DefaultCategory: String {
case Alert = "com.alecrim.AlecrimAsyncKit.MutuallyExclusiveTaskCondition.DefaultCategory.Alert"
case Alert = "_CAAAK.METC.DC.Alert"
}

private static var mutuallyExclusiveSemaphores = [String: (semaphore: dispatch_semaphore_t, count: Int)]()
private static var spinlock = OS_SPINLOCK_INIT
private static var mutuallyExclusiveSemaphores = [String : Semaphore]()

/// The category name that will define the condition exclusivity group.
public let categoryName: String

/// Initialize a condition for describing kinds of operations that may not execute concurrently.
///
/// - parameter defaultCategory: The default category enumeration member that will define the condition exclusivity group.
Expand All @@ -42,53 +52,47 @@ public final class MutuallyExclusiveTaskCondition: TaskCondition {
self.categoryName = categoryName

super.init() { result in
MutuallyExclusiveTaskCondition.wait(categoryName)
result(.Satisfied)
}
}

internal static func increment(categoryName: String) {
assert(!NSThread.isMainThread())

let semaphore: dispatch_semaphore_t
private static func wait(categoryName: String) {
let dispatch_semaphore: dispatch_semaphore_t

do {
withUnsafeMutablePointer(&self.spinlock, OSSpinLockLock)
defer {
withUnsafeMutablePointer(&self.spinlock, OSSpinLockUnlock)
}
defer { withUnsafeMutablePointer(&self.spinlock, OSSpinLockUnlock) }

if self.mutuallyExclusiveSemaphores[categoryName] == nil {
semaphore = dispatch_semaphore_create(1)
self.mutuallyExclusiveSemaphores[categoryName] = (semaphore, 1)
if let semaphore = self.mutuallyExclusiveSemaphores[categoryName] {
semaphore.count++
dispatch_semaphore = semaphore.dispatch_semaphore
}
else {
semaphore = self.mutuallyExclusiveSemaphores[categoryName]!.semaphore
self.mutuallyExclusiveSemaphores[categoryName]!.count++
let semaphore = Semaphore(dispatch_semaphore: dispatch_semaphore_create(1), count: 1)
self.mutuallyExclusiveSemaphores[categoryName] = semaphore
dispatch_semaphore = semaphore.dispatch_semaphore
}
}

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
dispatch_semaphore_wait(dispatch_semaphore, DISPATCH_TIME_FOREVER)
}

internal static func decrement(categoryName: String) {
let semaphore: dispatch_semaphore_t
internal static func signal(categoryName: String) {
let dispatch_semaphore: dispatch_semaphore_t

do {
withUnsafeMutablePointer(&self.spinlock, OSSpinLockLock)
defer {
withUnsafeMutablePointer(&self.spinlock, OSSpinLockUnlock)
}

semaphore = self.mutuallyExclusiveSemaphores[categoryName]!.semaphore

self.mutuallyExclusiveSemaphores[categoryName]!.count--

if self.mutuallyExclusiveSemaphores[categoryName]!.count == 0 {
self.mutuallyExclusiveSemaphores.removeValueForKey(categoryName)
}
withUnsafeMutablePointer(&self.spinlock, OSSpinLockLock)
defer { withUnsafeMutablePointer(&self.spinlock, OSSpinLockUnlock) }

let semaphore = self.mutuallyExclusiveSemaphores[categoryName]!
semaphore.count--
dispatch_semaphore = semaphore.dispatch_semaphore

if semaphore.count == 0 {
self.mutuallyExclusiveSemaphores[categoryName] = nil
}

dispatch_semaphore_signal(semaphore)
dispatch_semaphore_signal(dispatch_semaphore)
}

}
Loading

0 comments on commit ef93877

Please sign in to comment.