mirror of
https://github.com/google/promises
synced 2026-11-09 22:26:00 +05:45
Refine convenience constructor in Swift
This commit is contained in:
1 parent
08dde88400
commit
e10eaeb954
8 files changed
+58
-24
No files matched your search
@@ -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,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,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'
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in new issue
Block a user