Refine convenience constructor in Swift

This commit is contained in:
Anthony Shoumikhin committed 2018-05-10 11:12:20 -07:00
1 parent 08dde88400
commit e10eaeb954
8 files changed
+58 -24

No files matched your search

+3 -7
View File
@@ -23,18 +23,14 @@ enum PlaygroundError: Error {
}
func reverse(string: String) -> Promise<String> {
return Promise {
Thread.sleep(forTimeInterval: 0.1)
return String(string.reversed())
}
return Promise(String(string.reversed())).delay(0.1)
}
func number(from string: String) -> Promise<Int> {
return Promise {
Thread.sleep(forTimeInterval: 0.1)
return Promise { () -> Int in
guard let number = Int(string) else { throw PlaygroundError.invalidNumber }
return number
}
}.delay(0.1)
}
func square(number: Int) -> Int {
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'PromisesObjC'
s.version = '1.1.1'
s.version = '1.2'
s.authors = 'Google Inc.'
s.license = { :type => 'Apache', :file => 'LICENSE' }
s.homepage = 'https://github.com/google/promises'
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'PromisesSwift'
s.version = '1.1.1'
s.version = '1.2'
s.authors = 'Google Inc.'
s.license = { :type => 'Apache', :file => 'LICENSE' }
s.homepage = 'https://github.com/google/promises'
+24 -3
View File
@@ -15,14 +15,14 @@
import Foundation
public extension Promise {
public typealias Do = () throws -> Value
public typealias Do<Value> = () throws -> Value
/// Creates a pending promise to be resolved with the return value of `work` block which is
/// executed asynchronously on the given `queue`.
/// - parameters:
/// - queue: A queue to invoke the `work` block on.
/// - work: A block to perform any operations needed to resolve the promise.
public convenience init(on queue: DispatchQueue = .promises, _ work: @escaping Do) {
/// - work: A block that returns a value used to resolve the new promise.
public convenience init<Value>(on queue: DispatchQueue = .promises, _ work: @escaping Do<Value>) {
let objCPromise = ObjCPromise<AnyObject>.__onQueue(queue) {
do {
let resolution = try work()
@@ -35,4 +35,25 @@ public extension Promise {
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__pendingObjects?.add(self)
}
/// Creates a pending promise to be resolved with the same resolution as the promise returned from
/// `work` block which is executed asynchronously on the given `queue`.
/// - parameters:
/// - queue: A queue to invoke the `work` block on.
/// - work: A block that returns a promise used to resolve the new promise.
public convenience init<Value>(
on queue: DispatchQueue = .promises,
_ work: @escaping Do<Promise<Value>>
) {
let objCPromise = ObjCPromise<AnyObject>.__onQueue(queue) {
do {
return try work().objCPromise
} catch let error {
return error as NSError
}
}
self.init(objCPromise)
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__pendingObjects?.add(self)
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ import XCTest
class PromiseAwaitTests: XCTestCase {
func testPromiseAwaitFulfill() {
// Act.
let promise = Promise<Int>(on: .global()) {
let promise = Promise<Int>(on: .global()) { () -> Int in
let minusFive = try await(Harness.negate(5))
XCTAssertEqual(minusFive, -5)
let twentyFive = try await(Harness.multiply(minusFive, minusFive))
+10
View File
@@ -27,6 +27,16 @@ class PromiseDoTests: XCTestCase {
XCTAssertNil(promise.error)
}
func testPromiseDoReturnPromise() {
// Arrange & Act.
let promise = Promise<Int> { Promise(42) }
// Assert.
XCTAssert(waitForPromises(timeout: 10))
XCTAssertEqual(promise.value, 42)
XCTAssertNil(promise.error)
}
func testPromiseDoReject() {
// Arrange & Act.
let promise = Promise<Int> { throw Test.Error.code42 }
+1 -1
View File
@@ -80,7 +80,7 @@ class PromiseThenTests: XCTestCase {
var count = 0
// Act.
let promise = Promise<Int> {
let promise = Promise { () -> Int in
let number = 42
return number
}.then { value in
+17 -10
View File
@@ -414,7 +414,7 @@ In your `Package.swift` file, add `Promises` dependency to corresponding targets
let package = Package(
// ...
dependencies: [
.package(url: "https://github.com/google/promises.git", from: "1.1.1"),
.package(url: "https://github.com/google/promises.git", from: "1.2"),
],
// ...
)
@@ -443,13 +443,13 @@ Or, the module, if `CLANG_ENABLE_MODULES = YES`:
To use `Promises` for both Swift and Objective-C, add the following to your `Podfile`:
```ruby
pod 'PromisesSwift', '~> 1.1'
pod 'PromisesSwift', '~> 1.2'
```
To use `Promises` for Objective-C only, add the following to your `Podfile`:
```ruby
pod 'PromisesObjC', '~> 1.1'
pod 'PromisesObjC', '~> 1.2'
```
Also, don't forget to `use_frameworks!` in your target. Then, run `pod install`.
@@ -579,7 +579,7 @@ Swift:
```swift
let promise = Promise<String> { fulfill, reject in
// Called asynchronously on the main queue by default.
// Called asynchronously on the default queue.
if success {
fulfill("Hello world.")
} else {
@@ -593,7 +593,7 @@ Objective-C:
```objectivec
FBLPromise<NSString *> *promise = [FBLPromise async:^(FBLPromiseFulfillBlock fulfill,
FBLPromiseRejectBlock reject) {
// Called asynchronously on the main queue by default.
// Called asynchronously on the default queue.
if (success) {
fulfill(@"Hello world.");
} else {
@@ -604,14 +604,15 @@ FBLPromise<NSString *> *promise = [FBLPromise async:^(FBLPromiseFulfillBlock ful
##### Do
We can make the above examples even more concise with `do` operator if the block
of code inside a promise doesn't require async fulfillment:
We can make the above examples even more concise with the `do` operator
(which is implemented as a convenience constructor in Swift) if the promise
work block doesn't require async fulfillment:
Swift:
```swift
let promise = Promise<String> {
// Called asynchronously on the main queue by default.
let promise = Promise { () -> String in
// Called asynchronously on the default queue.
guard success else { throw someError }
return "Hello world"
}
@@ -621,11 +622,17 @@ Objective-C:
```objectivec
FBLPromise<NSString *> *promise = [FBLPromise do:^id {
// Called asynchronously on the main queue by default.
// Called asynchronously on the default queue.
return success ? @"Hello world" : someError;
}];
```
Note: In Swift the convenience constructor accepting a work block is overloaded
and can return either a value or another promise, which is eventually used to
resolve the newly created promise. In Objective-C the `do` operator return value
is not strongly typed, so you can return a value, another promise or an error
and expect the correct behavior.
##### Pending
And in case you need a pending promise without any async block of work