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/4.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
vmartinelli committed May 21, 2018
2 parents 425388a + 7dcfc0d commit bb43ba6
Show file tree
Hide file tree
Showing 15 changed files with 203 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 = "4.0-beta.5"
s.version = "4.0"
s.summary = "async and await for Swift."
s.homepage = "https://www.alecrim.com/AlecrimAsyncKit"

Expand Down
3 changes: 3 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import PackageDescription

let package = Package(name: "AlecrimAsyncKit")
16 changes: 7 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ async and await for Swift.

## Usage
### Awaiting the results
I know I am putting the cart before the horse, but... For the three functions in the next section you can await the returning value in the same way:
Maybe I am putting the cart before the horses, but... For all the functions in the next section you can await the returning value in the same way:

```swift
func someFuncRunningInBackground() throws {
Expand Down Expand Up @@ -161,21 +161,19 @@ func someFuncRunningInTheMainThread() {
}
```

All methods (`then`, `catch`, `cancelled` and `finally`) are optional. If specified, the closure related to the `finally` method will always be called regardless whether the task was cancelled or not, whether there was an error or not.
All methods (`then`, `catch`, `cancelled` and `finally`) are optional. When specified, the closure related to the `finally` method will always be called regardless whether the task was cancelled or not, whether there was an error or not.

## Non failable tasks
If you read the framework's code you will find the `NonFailableTask<Value>` class. This kind of task cannot fail (sort of). In fact it may fail, but it should not.

The main difference from the failable task class is that you do not have to use the `try` keyword when awaiting for non failable task results. A non failable task cannot be cancelled either.
The main difference from the failable task class is that you do not have to `try` when awaiting for non failable task results. A non failable task cannot be cancelled either.

Please only use this type of task when you are sure that it can not fail. If it do, your program will crash.
Please only use this type of task when you are sure that it cannot fail. If it do and the task fail your program will crash.

## Observers and conditions
The previous version had observers and conditions based on Session 226 of WWDC 2015 (“Advanced NSOperations”). This turned the framework unnecessarily complex.
## Dependencies, conditions and observers
The previous version had observers and conditions based on Session 226 of WWDC 2015 (“Advanced NSOperations”). This turned the framework unnecessarily complex. If you need this functionality right now you can use version 3.x of **AlecrimAsyncKit**.

If you need this functionality right now you can use version 3.x of **AlecrimAsyncKit**.

Observers and conditions may be reimplemented in a future release or as a separated framework. No guarantees, though.
In version 4.0 the framework has the notion of "dependencies" and a new kind of "conditions" was implemented. Observers may reappear in a future release. No guarantees, though.

## Contribute
If you have any problems or need more information, please open an issue using the provided GitHub link.
Expand Down
8 changes: 6 additions & 2 deletions Source/AlecrimAsyncKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
1466506C205B178F006C70AA /* Sequence+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1466506B205B178F006C70AA /* Sequence+Extensions.swift */; };
1466506E205B1905006C70AA /* OtherConveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1466506D205B1905006C70AA /* OtherConveniences.swift */; };
14A391242053A03300AD8249 /* Cancellation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A391232053A03300AD8249 /* Cancellation.swift */; };
14E8AD3B209FF6F20035DFA2 /* Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14E8AD3A209FF6F20035DFA2 /* Mapping.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -42,6 +43,7 @@
1466506B205B178F006C70AA /* Sequence+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sequence+Extensions.swift"; sourceTree = "<group>"; };
1466506D205B1905006C70AA /* OtherConveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OtherConveniences.swift; sourceTree = "<group>"; };
14A391232053A03300AD8249 /* Cancellation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cancellation.swift; sourceTree = "<group>"; };
14E8AD3A209FF6F20035DFA2 /* Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mapping.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -121,6 +123,7 @@
14665067205B1727006C70AA /* DispatchQueue+Extensions.swift */,
14665065205B1708006C70AA /* OperationQueue+Extensions.swift */,
1466506D205B1905006C70AA /* OtherConveniences.swift */,
14E8AD3A209FF6F20035DFA2 /* Mapping.swift */,
1466506B205B178F006C70AA /* Sequence+Extensions.swift */,
);
path = Convenience;
Expand Down Expand Up @@ -215,6 +218,7 @@
14665068205B1727006C70AA /* DispatchQueue+Extensions.swift in Sources */,
14665066205B1708006C70AA /* OperationQueue+Extensions.swift in Sources */,
143E712520531FBC002F7222 /* Async.swift in Sources */,
14E8AD3B209FF6F20035DFA2 /* Mapping.swift in Sources */,
143E712320531F9B002F7222 /* Errors.swift in Sources */,
1444522A209E09200016D444 /* TaskDependency.swift in Sources */,
1466506A205B1763006C70AA /* Availability.swift in Sources */,
Expand Down Expand Up @@ -360,7 +364,7 @@
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 356;
CURRENT_PROJECT_VERSION = 370;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
Expand Down Expand Up @@ -392,7 +396,7 @@
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 356;
CURRENT_PROJECT_VERSION = 370;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,43 +14,33 @@ import Foundation
// example:
//
// extension Reachability: TaskCondition {
// func evaluate() -> Task<Bool> {
// return conditionAsync { conditionTask in
// self.whenReachable {
// conditionTask.finish(with: true)
// }
// }
// public func evaluate() -> Bool {
// return self.connection != .none
// }
// }
//
// ...
//
// async(condition: Reachability()) { ... }
// async(condition: self.reachability) { ... }
//

public protocol TaskCondition {
func evaluate() -> Task<Bool>
}

// MARK: -

public func conditionAsync(execute closure: @escaping AsyncTaskClosure<Bool>) -> Task<Bool> {
return async(in: Queue.taskConditionOperationQueue, execute: closure)
}

public func conditionAsync(execute taskClosure: @escaping AsyncTaskFullClosure<Bool>) -> Task<Bool> {
return async(in: Queue.taskConditionOperationQueue, execute: taskClosure)
// this will always be executed on a background thread, so the result does not need to me immediately computed
func evaluate() -> Bool
}

// MARK: -

// boolean tasks can be used as conditions too

extension BaseTask: TaskCondition where Value == Bool {
public func evaluate() -> Task<Bool> {
return conditionAsync {
public func evaluate() -> Bool {
do {
return try self.await()
}
catch {
return false
}
}
}

Expand Down Expand Up @@ -104,35 +94,33 @@ public final class CompoundTaskCondition: TaskCondition {
self.subconditions = subconditions
}

public func evaluate() -> Task<Bool> {
return conditionAsync {
switch self.compoundTaskConditionType {
case .and:
var all = true
for subcondition in self.subconditions {
if !(try await(subcondition.evaluate())) {
all = false
break
}
public func evaluate() -> Bool {
switch self.compoundTaskConditionType {
case .and:
var all = true
for subcondition in self.subconditions {
if !subcondition.evaluate() {
all = false
break
}
}

return all
return all

case .or:
var any = false
for subcondition in self.subconditions {
if (try await(subcondition.evaluate())) {
any = true
break
}
case .or:
var any = false
for subcondition in self.subconditions {
if subcondition.evaluate() {
any = true
break
}
}

return any
return any

case .not:
let subcondition = self.subconditions.first!
return !(try await(subcondition.evaluate()))
}
case .not:
let subcondition = self.subconditions.first!
return !subcondition.evaluate()
}
}

Expand Down
20 changes: 10 additions & 10 deletions Source/AlecrimAsyncKit/Convenience/Availability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,33 @@

import Foundation

@available(*, deprecated, renamed: "async(in:execute:)")
@available(*, deprecated, renamed: "async(on:execute:)")
public func asyncEx<Value>(in queue: OperationQueue? = nil, execute closure: @escaping AsyncTaskFullClosure<Value>) -> Task<Value> {
return async(in: queue, execute: closure)
return async(on: queue, execute: closure)
}

@available(*, deprecated, renamed: "async(value:)")
public func asyncValue<Value>(in queue: OperationQueue? = nil, _ value: Value) -> Task<Value> {
return async(in: queue, value: value)
return async(on: queue, value: value)
}

@available(*, deprecated, renamed: "async(error:)")
public func asyncError<Value>(in queue: OperationQueue? = nil, _ error: Error) -> Task<Value> {
return async(in: queue, error: error)
return async(on: queue, error: error)
}

@available(*, deprecated, renamed: "async(in:delay:)")
@available(*, deprecated, renamed: "async(on:delay:)")
public func asyncDelay(in queue: OperationQueue? = nil, timeInterval: TimeInterval) -> NonFailableTask<Void> {
return async(in: queue, delay: timeInterval)
return async(on: queue, delay: timeInterval)
}

@available(*, deprecated, renamed: "async(in:sleepForTimeInterval:)")
@available(*, deprecated, renamed: "async(on:sleepForTimeInterval:)")
public func asyncSleep(in queue: OperationQueue? = nil, forTimeInterval timeInterval: TimeInterval) -> NonFailableTask<Void> {
return async(in: queue, sleepForTimeInterval: timeInterval)
return async(on: queue, sleepForTimeInterval: timeInterval)
}

@available(*, deprecated, renamed: "async(in:sleepUntil:)")
@available(*, deprecated, renamed: "async(on:sleepUntil:)")
public func asyncSleep(in queue: OperationQueue? = nil, until date: Date) -> NonFailableTask<Void> {
return async(in: queue, sleepUntil: date)
return async(on: queue, sleepUntil: date)
}

Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ import Foundation
extension DispatchQueue {

public func async<Value>(execute closure: @escaping AsyncTaskClosure<Value>) -> Task<Value> {
return AlecrimAsyncKit.async(in: Queue.operationQueue(for: self), execute: closure)
return AlecrimAsyncKit.async(on: Queue.operationQueue(for: self), execute: closure)
}

public func async<Value>(execute closure: @escaping AsyncNonFailableTaskClosure<Value>) -> NonFailableTask<Value> {
return AlecrimAsyncKit.async(in: Queue.operationQueue(for: self), execute: closure)
return AlecrimAsyncKit.async(on: Queue.operationQueue(for: self), execute: closure)
}

public func async<Value>(execute taskClosure: @escaping AsyncTaskFullClosure<Value>) -> Task<Value> {
return AlecrimAsyncKit.async(in: Queue.operationQueue(for: self), execute: taskClosure)
return AlecrimAsyncKit.async(on: Queue.operationQueue(for: self), execute: taskClosure)
}

public func async<Value>(execute taskClosure: @escaping AsyncTaskFullClosure<Value>) -> NonFailableTask<Value> {
return AlecrimAsyncKit.async(in: Queue.operationQueue(for: self), execute: taskClosure)
return AlecrimAsyncKit.async(on: Queue.operationQueue(for: self), execute: taskClosure)
}

}
68 changes: 68 additions & 0 deletions Source/AlecrimAsyncKit/Convenience/Mapping.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// Mapping.swift
// AlecrimAsyncKit
//
// Created by Vanderlei Martinelli on 06/05/18.
// Copyright © 2018 Alecrim. All rights reserved.
//

import Foundation

// MARK: -

extension Task {

public func map<U>(on queue: OperationQueue? = nil, closure: @escaping (Value) throws -> U) -> Task<U> {
return async(on: queue) {
let value = try self.await()
let mappedValue = try closure(value)

return mappedValue
}
}

public func map<U>(on queue: OperationQueue? = nil, closure: @escaping (Value) -> U) -> Task<U> {
return async(on: queue) {
let value = try self.await()
let mappedValue = closure(value)

return mappedValue
}
}

}

extension Task {

public func asNonFailable(on queue: OperationQueue? = nil) -> NonFailableTask<Value> {
return async(on: queue) {
return try! self.await()
}
}

}

// MARK: -

extension NonFailableTask {

public func map<U>(on queue: OperationQueue? = nil, closure: @escaping (Value) -> U) -> NonFailableTask<U> {
return async(on: queue) {
let value = try! self.await()
let mappedValue = closure(value)

return mappedValue
}
}

}

extension NonFailableTask {

public func asFailable(on queue: OperationQueue? = nil) -> Task<Value> {
return async(on: queue) {
return try self.await()
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ import Foundation
extension OperationQueue {

public func addOperation<Value>(_ closure: @escaping AsyncTaskClosure<Value>) -> Task<Value> {
return AlecrimAsyncKit.async(in: self, execute: closure)
return AlecrimAsyncKit.async(on: self, execute: closure)
}

public func addOperation<Value>(_ closure: @escaping AsyncNonFailableTaskClosure<Value>) -> NonFailableTask<Value> {
return AlecrimAsyncKit.async(in: self, execute: closure)
return AlecrimAsyncKit.async(on: self, execute: closure)
}

public func addOperation<Value>(_ taskClosure: @escaping AsyncTaskFullClosure<Value>) -> Task<Value> {
return AlecrimAsyncKit.async(in: self, execute: taskClosure)
return AlecrimAsyncKit.async(on: self, execute: taskClosure)
}

public func addOperation<Value>(_ taskClosure: @escaping AsyncTaskFullClosure<Value>) -> NonFailableTask<Value> {
return AlecrimAsyncKit.async(in: self, execute: taskClosure)
return AlecrimAsyncKit.async(on: self, execute: taskClosure)
}

}
Loading

0 comments on commit bb43ba6

Please sign in to comment.