### Swift Async Code Example Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates the traditional nested completion handler pattern for asynchronous operations in Swift, showing its potential for complexity. ```swift func getCurrentUserContactsAvatars(_ completion: ([UIImage]?, Error?) -> Void) { MyClient.getCurrentUser() { currentUser, error in guard error == nil else { completion(nil, error) return } MyClient.getContacts(currentUser) { contacts, error in guard error == nil else { completion(nil, error) return } guard let contacts = contacts, !contacts.isEmpty() else { completion([UIImage](), nil) return } var count = contacts.count var avatars = [UIImage](repeating: nil, count: count) var errorReported = false for (index, contact) in contacts.enumerated() { MyClient.getAvatar(contact) { avatar, error in if (errorReported) { return } guard error == nil else { completion(nil, error) errorReported = true return } if let avatar = avatar { avatars[index] = avatar } count -= 1 if count == 0 { completion(avatars.flatMap { $0 }, nil) } } } } } } ``` -------------------------------- ### Install PromisesSwift with CocoaPods Source: https://github.com/google/promises/blob/master/g3doc/index.md Add this line to your Podfile to use Promises for both Swift and Objective-C. Ensure `use_frameworks!` is also present. ```ruby pod 'PromisesSwift' ``` -------------------------------- ### Objective-C Async Code Example Source: https://github.com/google/promises/blob/master/g3doc/index.md Illustrates the traditional nested completion handler pattern for asynchronous operations in Objective-C, highlighting potential complexity. ```objectivec - (void)getCurrentUserContactsAvatars:(void (^)(NSArray *, NSError *))completion { [MyClient getCurrentUserWithCompletion:^(MyUser *currentUser, NSError *error) { if (error) { completion(nil, error); return; } [MyClient getContactsForUser:currentUser completion:^(NSArray *contacts, NSError *error) { if (error) { completion(nil, error); return; } if (contacts.count == 0) { completion(@[], nil); return; } NSMutableArray *avatars = [NSMutableArray array]; NSUInteger __block count = contacts.count; BOOL __block errorReported = NO; for (NSUInteger index = 0; index < count; ++index) { [avatars addObject:[NSNull null]]; } [contacts enumerateObjectsUsingBlock:^(MyContact *contact, NSUInteger index, BOOL __unused *_) { [MyClient getAvatarForContact:contact completion:^(UIImage *avatar, NSError *error) { if (errorReported) { return; } if (error) { completion(nil, error); errorReported = YES; return; } if (avatar) { avatars[index] = avatar; } if (--count == 0) { completion(avatars, nil); } }]; }]; }]; }]; } ``` -------------------------------- ### Install PromisesObjC with CocoaPods Source: https://github.com/google/promises/blob/master/g3doc/index.md Add this line to your Podfile to use Promises for Objective-C only. Ensure `use_frameworks!` is also present. ```ruby pod 'PromisesObjC' ``` -------------------------------- ### Swift Promise-based API Source: https://github.com/google/promises/blob/master/g3doc/index.md Example of a Swift function returning a Promise for asynchronous operations. ```swift func data(at url: URL) -> Promise ``` -------------------------------- ### Objective-C Promise-based API Source: https://github.com/google/promises/blob/master/g3doc/index.md Example of an Objective-C method returning an FBLPromise for asynchronous operations. ```objectivec - (FBLPromise *)getDataAtURL:(NSURL *)anURL; ``` -------------------------------- ### Swift Completion Block API Source: https://github.com/google/promises/blob/master/g3doc/index.md Example of a traditional Swift function using a completion block for asynchronous operations. ```swift func data(at url: URL, completion: @escaping (Data?, Error?) -> Void) ``` -------------------------------- ### Objective-C Completion Block API Source: https://github.com/google/promises/blob/master/g3doc/index.md Example of a traditional Objective-C method using a completion block for asynchronous operations. ```objectivec - (void)getDataAtURL:(NSURL *)anURL completion:^(NSData *data, NSError *error)completion; ``` -------------------------------- ### Chaining Asynchronous Operations with Promises in Swift Source: https://github.com/google/promises/blob/master/g3doc/index.md Achieves the same asynchronous operation chaining as the Objective-C example using Swift's Promise syntax. Assumes `all` and `map` functions are available. ```swift func getCurrentUserContactsAvatars() -> Promise<[UIImage]> { return MyClient.getCurrentUser().then(MyClient.getContacts).then { contacts in all(contacts.map(MyClient.getAvatar)) } } ``` -------------------------------- ### Swift: Basic Promise Chaining with Then Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates chaining promises in Swift using the 'then' operator. Shows how to handle resolved values, return new promises, values, or throw errors. ```swift let numberPromise = Promise(42) // Return another promise. let chainedStringPromise = numberPromise.then { number in return self.string(from: number) } // Return any value. let chainedStringPromise = numberPromise.then { number in return String(number) } // Throw an error. let chainedStringPromise = numberPromise.then { number in throw NSError(domain: "", code: 0, userInfo: nil) } // Void return. let chainedStringPromise = numberPromise.then { number in print(number) // Implicit 'return number' here. } ``` -------------------------------- ### Create Pending Promise and Chain Observer (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates creating a pending promise and chaining an observer block that captures 'self', potentially creating a retain cycle. The promise is resolved later. ```objectivec @implementation MyClass { FBLPromise *_promise; } - (FBLPromise *)doSomething { if (_promise == nil) { _promise = [FBLPromise pendingPromise]; } return [_promise then:^id(id number) { return [self doSomethingElse:number]; }]; } - (NSString *)doSomethingElse:(NSNumber *)number { return number.stringValue; } @end ``` -------------------------------- ### Import Promises in Objective-C (Bazel - Module) Source: https://github.com/google/promises/blob/master/g3doc/index.md Import the FBLPromises module if enable_modules is set to True in Bazel. ```objectivec @import FBLPromises; ``` -------------------------------- ### Objective-C: Promise Pipeline Chaining Source: https://github.com/google/promises/blob/master/g3doc/index.md Shows how to chain multiple asynchronous tasks sequentially in Objective-C using the 'then' operator to create a promise pipeline. ```objectivec - (FBLPromise *)work1:(NSString *)string { return [FBLPromise do:^id { return string; }]; } - (FBLPromise *)work2:(NSString *)string { return [FBLPromise do:^id { return @(string.integerValue); }]; } - (NSNumber *)work3:(NSNumber *)number { return @(number.integerValue * number.integerValue); } [[[[self work1:@"10"] then:^id(NSString *string) { return [self work2:string]; }] then:^id(NSNumber *number) { return [self work3:number]; }] then:^id(NSNumber *number) { NSLog(@"%@", number); // 100 return number; }]; ``` -------------------------------- ### Objective-C Promises with Dot-Syntax Source: https://github.com/google/promises/blob/master/g3doc/index.md Illustrates the use of dot-syntax for chaining Objective-C promises, simplifying the appearance of promise chains by reducing bracket usage. ```objectivec [self work1:@"abc"] .then(^id(NSString *string) { return [self work2:string]; }) .then(^id(NSNumber *number) { return [self work3:number]; }) .then(^id(NSNumber *number) { NSLog(@"%@", number); return nil; }) .catch(^(NSError *error) { NSLog(@"Cannot convert string to number: %@", error); }); ``` -------------------------------- ### Objective-C: Basic Promise Chaining with Then Source: https://github.com/google/promises/blob/master/g3doc/index.md Illustrates chaining promises in Objective-C using the 'then' operator. Covers returning promises, values, or errors from the block. ```objectivec FBLPromise *numberPromise = [FBLPromise resolvedWith:@42]; // Return another promise. FBLPromise *chainedStringPromise = [numberPromise then:^id(NSNumber *number) { return [self stringFromNumber:number]; }]; // Return any value. FBLPromise *chainedStringPromise = [numberPromise then:^id(NSNumber *number) { return [number stringValue]; }]; // Return an error. FBLPromise *chainedStringPromise = [numberPromise then:^id(NSNumber *number) { return [NSError errorWithDomain:@"" code:0 userInfo:nil]; }]; // Fake void return. FBLPromise *chainedStringPromise = [numberPromise then:^id(NSNumber *number) { NSLog(@"%@", number); return nil; // OR return number; }]; ``` -------------------------------- ### Create Pending Promise and Chain Observer (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates creating a pending promise and chaining an observer block that captures 'self', potentially creating a retain cycle. The promise is resolved later. ```swift class MyClass { var promise: Promise? func doSomething() -> Promise { if promise == nil { promise = Promise.pending() } return promise?.then(doSomethingElse) } func doSomethingElse(number: Int) -> String { return String(number) } } ``` -------------------------------- ### Objective-C: Then on Custom Dispatch Queue Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates executing 'then' blocks on a specified queue in Objective-C using the 'onQueue:then:' method. ```objectivec [numberPromise onQueue:backgroundQueue then:^id(NSNumber *number) { return number.stringValue; }]; ``` -------------------------------- ### Swift: Promise Pipeline Chaining Source: https://github.com/google/promises/blob/master/g3doc/index.md Illustrates chaining multiple asynchronous operations into a pipeline using 'then' in Swift. This simulates synchronous execution flow. ```swift func work1(_ string: String) -> Promise { return Promise { return string } } func work2(_ string: String) -> Promise { return Promise { return Int(string) ?? 0 } } func work3(_ number: Int) -> Int { return number * number } work1("10").then { string in return work2(string) }.then { number in return work3(number) }.then { number in print(number) // 100 } ``` ```swift work1("10").then(work2).then(work3).then { number in print(number) // 100 } ``` -------------------------------- ### Swift Usage of Async Function Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates how to invoke the previously defined asynchronous function in Swift and manage its results or errors. ```swift override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) getCurrentUserContactsAvatars() { avatars, error in if (error) { showErrorAlert(error) } else { updateAvatars(avatars) } } } ``` -------------------------------- ### Wrap Async Method to Return a Promise (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Converts a method using a typical callback pattern into a promise. ```objectivec - (FBLPromise *)newAsyncMethodReturningAPromise { return [FBLPromise wrapObjectOrErrorCompletion:^(FBLPromiseObjectOrErrorCompletion handler) { [MyClient wrappedAsyncMethodWithTypicalCompletion:handler]; }]; } ``` -------------------------------- ### Swift: Then on Custom Dispatch Queue Source: https://github.com/google/promises/blob/master/g3doc/index.md Shows how to execute 'then' blocks on a custom dispatch queue in Swift for asynchronous operations. ```swift numberPromise.then(on: backgroundQueue) { number in return String(number) } ``` -------------------------------- ### Wait for all promises of different types to fulfill (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Use `FBLPromise all` to fetch heterogeneous data like location and avatar for a contact. The results are returned in an array, preserving the order of the input promises. ```objectivec [[FBLPromise all:@[ [MyClient getLocationForContact:contact], [MyClient getAvatarForContact:contact] ]] then:^id(NSArray *locationAndAvatar) { [self updateContactLocation:locationAndAvatar.firstObject andAvatar:locationAndAvatar.lastObject]; return nil; }]; ``` -------------------------------- ### Swift Usage of Objective-C Promises Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates how to bridge Objective-C promise-returning methods into Swift. This includes creating Swift Promises from Objective-C promises and passing Swift Promises back to Objective-C. ```swift let objc = ObjCTest() Promise(objc.getString()).then { string in return Promise(objc.getNumber(string)) }.then { number in print(number) } wrap { handler in objc.async(with: "hello", and: 42, completion: handler) }.then { _ in print("Success.") }.catch { error in print(error) } let stringPromise = Promise { return "Hello world!" } objc.needsAPromise(stringPromise.asObjCPromise()) @objc(providesAPromiseFromNumber:) func providesAPromise(from number: Int) -> Promise.ObjCPromise { return Promise { "The number is \(number)" }.asObjCPromise() } objc.needsAPromise(providesAPromise(42)) ``` -------------------------------- ### Wrap Async Method to Return a Promise (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Converts a method using a typical callback pattern into a promise. ```swift func newAsyncMethodReturningAPromise() -> Promise { return wrap { handler in MyClient.wrappedAsyncMethodWithTypical(completion: handler) } } ``` -------------------------------- ### Wait for all promises of different types to fulfill (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Use `all` to fetch heterogeneous data like location and avatar for a contact. The results are returned as a tuple in the order of the input promises. ```swift all( MyClient.getLocationFor(contact: contact), MyClient.getAvatarFor(contact: contact) ).then { location, avatar in self.updateContact(location, avatar) } ``` -------------------------------- ### Using Chained Promises with Error Handling in Swift Source: https://github.com/google/promises/blob/master/g3doc/index.md Shows the Swift equivalent of consuming a Promise chain, updating UI on success and displaying an error alert on failure. ```swift override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) getCurrentUserContactsAvatars().then(updateAvatars).catch(showErrorAlert) } ``` -------------------------------- ### Import Promises in Objective-C (Bazel - Umbrella Header) Source: https://github.com/google/promises/blob/master/g3doc/index.md Import the umbrella header for FBLPromises in your Objective-C code when using Bazel. ```objectivec #import "path/to/Promises/FBLPromises.h" ``` -------------------------------- ### Create Pending Promise with Default Dispatch Queue (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Create a pending FBLPromise using the default dispatch queue by using the `async:` initializer. The work block will be executed asynchronously on the default queue. ```objectivec FBLPromise *promise = [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { // Called asynchronously on the default queue. if (success) { fulfill(@"Hello world."); } else { reject(someError); } }]; ``` -------------------------------- ### Import Promises in Swift (Bazel) Source: https://github.com/google/promises/blob/master/g3doc/index.md Import the Promises module in your Swift code when using Bazel. ```swift import Promises ``` -------------------------------- ### Import Promises in Objective-C (Umbrella Header) Source: https://github.com/google/promises/blob/master/g3doc/index.md Alternatively, import the FBLPromises umbrella header in your Objective-C code. ```objectivec #import ``` -------------------------------- ### Create Promise Returning Another Promise (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Objective-C's 'do' operator handles returning another promise or an error, ensuring correct behavior. ```objectivec FBLPromise *promise = [FBLPromise do:^id { // Called asynchronously on the default queue. return success ? [self someOtherOperation] : someError; }]; ``` -------------------------------- ### Using Chained Promises with Error Handling Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates how to consume the Promise returned by `getCurrentUserContactsAvatars`, including handling successful results and errors. ```objectivec - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [[[self getCurrentUserContactsAvatars] then:^id(NSArray *avatars) { [self updateAvatars:avatars]; return avatars; }] catch:^(NSError *error) { [self showErrorAlert:error]; }]; } ``` -------------------------------- ### Avoid Nested Promises (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates the anti-pattern of nesting promises in Swift. This structure can become difficult to read and manage. ```swift loadSomething().then { something in self.loadAnother().then { another in self.doSomething(with: something, and: another) } } ``` -------------------------------- ### Retry a Promise with Custom Settings (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Specifies a custom queue, max retry attempts, delay interval, and an optional predicate for early bail. ```objectivec dispatch_queue_t customQueue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0); [[[FBLPromise onQueue:customQueue attempts:5 delay:2.0 condition:^BOOL(NSInteger remainingAttempts, NSError *error) { return error.code == NSURLErrorNotConnectedToInternet; } retry:^id { return [self fetchWithURL:url]; }] then:^id(NSArray *values) { // Will enter `then` block if one of the retry attempts succeeds. NSLog(@"%@", values); return nil; }] catch:^(NSError *error) { // Will enter `catch` block if all retry attempts have been exhausted or the // given condition was not met. NSLog(@"%@", error); }]; ``` -------------------------------- ### Create a Resolved Promise with Nil (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Initialize a promise with a value (like nil) directly in the constructor to create an already fulfilled promise. ```swift func data(at url: URL) -> Promise { if url.absoluteString.isEmpty { return Promise(nil) } return load(url) } ``` -------------------------------- ### Objective-C Usage of Async Function Source: https://github.com/google/promises/blob/master/g3doc/index.md Shows how to call the previously defined asynchronous function in Objective-C and handle its completion. ```objectivec - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self getCurrentUserContactsAvatars:^(NSArray *avatars, NSError *error) { if (error) { [self showErrorAlert:error]; } else { [self updateAvatars:avatars]; } }]; } ``` -------------------------------- ### Create Pending Promise with Specific Dispatch Queue (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Create a pending FBLPromise by passing a work block to the `onQueue:async:` initializer, specifying the dispatch queue. The block should invoke `fulfill` or `reject` upon completion of asynchronous work. ```objectivec FBLPromise *promise = [FBLPromise onQueue:dispatch_get_main_queue() async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { // Called asynchronously on the dispatch queue specified. if (success) { // Resolve with a value. fulfill(@"Hello world."); } else { // Resolve with an error. reject(someError); } }]; ``` -------------------------------- ### Avoid Nested Promises (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Illustrates the anti-pattern of nesting promises in Objective-C. This approach leads to complex and hard-to-maintain code. ```objectivec [[self loadSomething] then:^id(NSData *something) { return [[self loadAnother] then:^id(NSData *another) { return [self doSomethingWith:something andAnother:another]; }]; }]; ``` -------------------------------- ### Use 'all' Operator for Multiple Promises (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Shows how to use the 'all' operator to handle results from multiple promises concurrently in Swift. This avoids nesting. ```swift all([loadSomething(), loadAnother()]).then { result in self.doSomething(with: result.first, and: result.last) } ``` -------------------------------- ### Retry a Promise with Default Settings (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Reattempts a task if the promise is initially rejected. Defaults to one retry attempt after a one-second delay. ```objectivec - (FBLPromise *)fetchWithURL:(NSURL *)url { return [FBLPromise wrap2ObjectsOrErrorCompletion:^(FBLPromise2ObjectsOrErrorCompletion handler) { [NSURLSession.sharedSession dataTaskWithURL:url completionHandler:handler]; }]; } NSURL *url = [NSURL URLWithString:@"https://myurl.com"]; // Defaults to one retry attempt after a one second delay. [[[FBLPromise retry:^id { return [self fetchWithURL:url]; }] then:^id(NSArray *values) { NSLog(@"%@", values); return nil; }] catch:^(NSError *error) { NSLog(@"%@", error); }]; ``` -------------------------------- ### Create Promise with Synchronous Work (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md The 'do' operator in Objective-C can return a value, another promise, or an error. The return value is not strongly typed. ```objectivec FBLPromise *promise = [FBLPromise do:^id { // Called asynchronously on the default queue. return success ? @"Hello world" : someError; }]; ``` -------------------------------- ### Import Promises in Objective-C (Swift Package Manager - Umbrella Header) Source: https://github.com/google/promises/blob/master/g3doc/index.md Import the umbrella header for FBLPromises in your Objective-C code when using Swift Package Manager. ```objectivec #import "FBLPromises.h" ``` -------------------------------- ### Use 'all' Operator for Multiple Promises (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates using the 'all' operator in Objective-C to manage multiple promises without nesting. This simplifies concurrent operations. ```objectivec [[FBLPromise all:@[ [self loadSomething], [self loadAnother] ]] then:^id(NSArray *result) { return [self doSomethingWith:result.firstObject andAnother:result.lastObject]; }]; ``` -------------------------------- ### Add Promises to Cartfile Source: https://github.com/google/promises/blob/master/g3doc/index.md Add the Promises library to your Cartfile for Carthage integration. Follow Carthage instructions for building and linking. ```plaintext github "google/promises" ``` -------------------------------- ### Retry a Promise with Custom Settings Source: https://github.com/google/promises/blob/master/g3doc/index.md Specifies a custom queue, max retry attempts, delay interval, and an optional predicate for early bail. ```swift let customQueue = DispatchQueue(label: "CustomQueue", qos: .userInitiated) retry( on: customQueue, attempts: 5, delay: 2, condition: { remainingAttempts, error in (error as NSError).code == URLError.notConnectedToInternet.rawValue } ) { fetch(url) }.then { values in // Will enter `then` block if one of the retry attempts succeeds. print(values) }.catch { error in // Will enter `catch` block if all retry attempts have been exhausted or the // given condition was not met. print(error) } ``` -------------------------------- ### Wait for all promises of the same type to fulfill (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Use `FBLPromise all` with `fbl_map` to concurrently fetch avatars for multiple contacts. The results are ordered according to the input promises. ```objectivec [[FBLPromise all:[contacts fbl_map:^id(MyContact *contact) { return [MyClient getAvatarForContact:contact]; }]] then:^id(NSArray *avatars) { [self updateAvatars:avatars]; return nil; }]; ``` -------------------------------- ### Create Pending Promise with Default Dispatch Queue (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Create a pending promise using the default dispatch queue by omitting the `on:` parameter. The work block will be executed asynchronously on the default queue. ```swift let promise = Promise { fulfill, reject in // Called asynchronously on the default queue. if success { fulfill("Hello world.") } else { reject(someError) } } ``` -------------------------------- ### Create Promise Returning Another Promise (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md In Swift, the 'do' operator's work block can return a value or another promise, which is then used to resolve the newly created promise. ```swift let promise = Promise { () -> Promise in // Called asynchronously on the default queue. guard success else { throw someError } return someOtherOperation() } ``` -------------------------------- ### Add Promises to Bazel Objective-C Library Source: https://github.com/google/promises/blob/master/g3doc/index.md Include the FBLPromises target in the deps of your objc_library in Bazel. ```python objc_library( # ... deps = [ "//path/to/Promises:FBLPromises", ], # ... ) ``` -------------------------------- ### Create a Pending Promise (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Use the 'pendingPromise' class method in Objective-C to create a promise that can be resolved manually later. Be mindful of potential retain cycles. ```objectivec FBLPromise *promise = [FBLPromise pendingPromise]; // ... if (success) { [promise fulfill:@"Hello world"]; } else { [promise reject:someError]; } ``` -------------------------------- ### Add Promises to Bazel Swift Library Source: https://github.com/google/promises/blob/master/g3doc/index.md Include the Promises target in the deps of your swift_library in Bazel. ```python swift_library( # ... deps = [ "//path/to/Promises", ], # ... ) ``` -------------------------------- ### Add Promises to Swift Package Manager Source: https://github.com/google/promises/blob/master/g3doc/index.md Add the Promises library as a dependency in your Package.swift file for Swift Package Manager. ```swift let package = Package( // ... dependencies: [ .package(url: "https://github.com/google/promises.git", from: "2.4.0"), ], // ... ) ``` -------------------------------- ### Wait for all promises of the same type to fulfill (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Use `all` to concurrently fetch data for multiple contacts and update avatars. The results are ordered according to the input promises. ```swift all(contacts.map { MyClient.getAvatarFor(contact: $0) }).then(updateAvatars) ``` -------------------------------- ### Chaining Observer Capturing Instance (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Shows a retain cycle where a promise observer block captures the 'myClass' instance, which in turn owns the promise. This cycle is not broken until the promise is resolved. ```objectivec [[myClass doSomething] then:^id(NSString *string) { [myClass doSomeOtherThing]; }]; ``` -------------------------------- ### Create a Resolved Promise with Nil (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Use '[FBLPromise resolvedWith:nil]' to create an already fulfilled promise with a nil value when a condition is met. ```objectivec - (FBLPromise *)getDataAtURL:(NSURL *)anURL { if (anURL.absoluteString.length == 0) { return [FBLPromise resolvedWith:nil]; } return [self loadURL:anURL]; } ``` -------------------------------- ### Retry a Promise with Default Settings Source: https://github.com/google/promises/blob/master/g3doc/index.md Reattempts a task if the promise is initially rejected. Defaults to one retry attempt after a one-second delay. ```swift func fetch(_ url: URL) -> Promise<(Data?, URLResponse?)> { return wrap { URLSession.shared.dataTask(with: url, completionHandler: $0).resume() } } let url = URL(string: "https://myurl.com")! // Defaults to one retry attempt after a one second delay. retry { fetch(url) }.then { print($0) }.catch { print($0) } ``` -------------------------------- ### Avoid Broken Promise Chains in Swift Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates the correct way to chain promises in Swift by returning the result of the final `then` call. This ensures that any errors in subsequent operations are properly caught. ```swift func asyncCall() -> Promise { let promise = doSomethingAsync() return promise.then(processData) } ``` -------------------------------- ### Catching Errors in an Objective-C Promise Pipeline Source: https://github.com/google/promises/blob/master/g3doc/index.md Illustrates error handling in Objective-C using the `catch` operator within a promise chain. Rejections are automatically propagated, and the `catch` block handles the error, bypassing intermediate `then` blocks. ```objectivec - (FBLPromise *)work1:(NSString *)string { return [FBLPromise do:^id { return string; }]; } - (FBLPromise *)work2:(NSString *)string { return [FBLPromise do:^id { NSInteger number = string.integerValue; return number > 0 ? @(number) : [NSError errorWithDomain:@"" code:0 userInfo:nil]; }]; } - (NSNumber *)work3:(NSNumber *)number { return @(number.integerValue * number.integerValue); } [[[[[self work1:@"abc"] then:^id(NSString *string) { return [self work2:string]; }] then:^id(NSNumber *number) { return [self work3:number]; // Never executed. }] then:^id(NSNumber *number) { NSLog(@"%@", number); // Never executed. return number; }] catch:^(NSError *error) { NSLog(@"Cannot convert string to number: %@", error); }]; ``` -------------------------------- ### Create Pending Promise with Specific Dispatch Queue (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Create a pending promise by passing a work block to the `Promise` initializer, specifying the dispatch queue. The block should call `fulfill` or `reject` when the asynchronous work is complete. ```swift let promise = Promise(on: .main) { fulfill, reject in // Called asynchronously on the dispatch queue specified. if success { // Resolve with a value. fulfill("Hello world.") } else { // Resolve with an error. reject(someError) } } ``` -------------------------------- ### Catching Errors in a Swift Promise Pipeline Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates how the `catch` operator in Swift can handle errors propagated through a chain of `then` blocks. Any rejection in the chain will skip subsequent `then` blocks and be caught by the `catch` operator. ```swift struct CustomError: Error {} func work1(_ string: String) -> Promise { return Promise { return string } } func work2(_ string: String) -> Promise { return Promise { guard let number = Int(string), number > 0 else { throw CustomError() } return number } } func work3(_ number: Int) -> Int { return number * number } work1("abc").then { string in return work2(string) }.then { number in return work3(number) // Never executed. }.then { number in print(number) // Never executed. }.catch { error in print("Cannot convert string to number: \(error)") } ``` -------------------------------- ### Set Default Dispatch Queue (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Sets the global dispatch queue as the default for all Promise operations. Use this when the main queue is busy with a custom run loop. ```objectivec FBLPromise.defaultDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); ``` -------------------------------- ### Execute code after promise pipeline regardless of outcome (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Use `always` to ensure a cleanup or finalization task runs after a promise chain, whether it succeeds or fails. This is useful for UI updates or logging. ```objectivec [[[[self getCurrentUserContactsAvatars] then:^id(NSArray *avatars) { [self updateAvatars:avatars]; return avatars; }] catch:^(NSError *error) { [self showErrorAlert:error]; }] always:^{ self.label.text = @"All done."; }]; ``` -------------------------------- ### Group nested 'all' calls in Swift Source: https://github.com/google/promises/blob/master/g3doc/index.md When needing more than 4 heterogeneous promises, break them into smaller `all` calls and then group their results using another `all` call. ```swift all(all(p1, p2, p3), all(p4, p5, p6)).then { results in let ((a1, a2, a3), (a4, a5, a6)) = results print(a1, a2, a3, a4, a5, a6) } ``` -------------------------------- ### Execute code after promise pipeline regardless of outcome (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Use `always` to ensure a cleanup or finalization task runs after a promise chain, whether it succeeds or fails. ```swift getCurrentUserContactsAvatars().then { avatars in self.update(avatars) }.catch { error in self.showErrorAlert(error) }.always { self.label.text = "All done." } ``` -------------------------------- ### Avoid Broken Promise Chains in Objective-C Source: https://github.com/google/promises/blob/master/g3doc/index.md Shows the correct pattern for chaining promises in Objective-C by returning the result of the last `then` block. This is essential for proper error handling in asynchronous operations. ```objectivec - (FBLPromise *)asyncCall { FBLPromise *promise = [self doSomethingAsync]; return [promise then:^id(NSData *result) { return [self processData:result]; }]; } ``` -------------------------------- ### Chaining Asynchronous Operations with Promises Source: https://github.com/google/promises/blob/master/g3doc/index.md Converts a sequence of asynchronous operations into a Promise chain. Assumes the availability of the `fbl_map` method on NSArray. ```objectivec - (FBLPromise *> *)getCurrentUserContactsAvatars { return [[[MyClient getCurrentUser] then:^id(MyUser *currentUser) { return [MyClient getContactsForUser:currentUser]; }] then:^id(NSArray *contacts) { return [FBLPromise all:[contacts fbl_map:^id(MyContact *contact) { return [MyClient getAvatarForContact:contact]; }]]; }]; } ``` -------------------------------- ### Objective-C: Any with Same Type Promises Source: https://github.com/google/promises/blob/master/g3doc/index.md Process an array of Objective-C promises of the same type using 'any'. The resulting array contains values or errors from the resolved promises. ```objectivec // Promises of same type: [[FBLPromise any:[contacts fbl_map:^id(MyContact *contact) { return [MyClient getAvatarForContact:contact]; }]] then:^id(NSArray *avatarsOrErrors) { [self updateAvatars:[avatarsOrErrors fbl_filter:^BOOL(id avatar) { return [avatar isKindOfClass:[UIImage class]]; }]]; return nil; }]; ``` -------------------------------- ### Refactor Nested Promises into Separate Method (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Illustrates refactoring nested promise logic into a separate method in Objective-C for better code organization and clarity. ```objectivec [[self loadSomething] then:^id(NSData *something) { return [self loadAnotherWithSomething:something]; }]; - (FBLPromise *)loadAnotherWithSomething:(NSData *)something { return [[self loadAnother] then:^id(NSData *another) { return [self doSomethingWith:something andAnother:another]; }]; } ``` -------------------------------- ### Objective-C: Any with Different Type Promises Source: https://github.com/google/promises/blob/master/g3doc/index.md Handle Objective-C promises of different types with 'any'. The resulting array contains the values or errors from the resolved promises, allowing for conditional logic. ```objectivec // Promises of different types: [[FBLPromise any:@[ [MyClient getLocationForContact:contact], [MyClient getAvatarForContact:contact] ]] then:^id(NSArray *locationAndAvatarOrErrors) { id location = locationAndAvatarOrErrors.firstObject; id avatar = locationAndAvatarOrErrors.lastObject; if ([location isKindOfClass:[CLLocation class]] && [avatar isKindOfClass:[UIImage class]]) { [self updateContactLocation:location andAvatar:avatar]; } else { // Optionally handle errors if needed. if ([location isKindOfClass:[NSError class]]) { [self showErrorAlert:location]; } if ([avatar isKindOfClass:[NSError class]]) { [self showErrorAlert:avatar]; } } return nil; }]; ``` -------------------------------- ### Create a Pending Promise (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Use the 'pending()' static function to create a promise without an associated asynchronous block, allowing for manual resolution later. Beware of potential retain cycles. ```swift let promise = Promise.pending() // ... if success { promise.fulfill("Hello world") } else { promise.reject(someError) } ``` -------------------------------- ### Swift: Any with Different Type Promises Source: https://github.com/google/promises/blob/master/g3doc/index.md Handle promises of heterogeneous types using 'any'. The result is a tuple of 'Maybe' enums, allowing individual handling of values or errors for each promise. ```swift // Promises of different types: any( MyClient.getLocationFor(contact: contact), MyClient.getAvatarFor(contact: contact) ).then { location, avatar in if let location = location.value, let avatar = avatar.value { self.updateContact(location, avatar) } else { // Optionally handle errors if needed. if let locationError = location.error { self.showErrorAlert(locationError) } if let avatarError = avatar.error { self.showErrorAlert(avatarError) } } } ``` -------------------------------- ### Swift: Chaining 'any' for More Than 3 Heterogeneous Promises Source: https://github.com/google/promises/blob/master/g3doc/index.md When needing to handle more than 3 heterogeneous promises in Swift, chain multiple 'any' calls. This allows grouping promises into smaller sets before combining their results. ```swift any( any(p1, p2), any(p3, p4)).then { results in dump(results) // a tuple containing two MayBe's. each contains their respective MayBe values } ``` -------------------------------- ### Synchronously Wait for Promise Resolution with FBLPromiseAwait Source: https://github.com/google/promises/blob/master/g3doc/index.md Use FBLPromiseAwait to synchronously wait for a promise to resolve on a different thread in Objective-C. Ensure proper error handling and consider using a concurrent queue for safety. ```objectivec [[[FBLPromise do:^id { NSError *error; NSNumber *minusFive = FBLPromiseAwait([calculator negate:@5], &error); if (error) return error; NSNumber *twentyFive = FBLPromiseAwait([calculator multiply:minusFive by:minusFive], &error); if (error) return error; NSNumber *twenty = FBLPromiseAwait([calculator add:twentyFive to:minusFive], &error); if (error) return error; NSNumber *five = FBLPromiseAwait([calculator subtract:twentyFive from:twenty], &error); if (error) return error; NSNumber *zero = FBLPromiseAwait([calculator add:minusFive to:five], &error); if (error) return error; NSNumber *result = FBLPromiseAwait([calculator multiply:zero by:five], &error); if (error) return error; return result; }] then:^id(NSNumber *result) { // ... }] catch:^(NSError *error) { // ... }]; ``` ```objectivec [FBLPromise onQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT) do:^id { NSError *error; id result = FBLPromiseAwait([object someAsyncRoutine], &error); return error ?: result; }]; ``` -------------------------------- ### Chaining Observer Capturing Instance (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Shows a retain cycle where a promise observer block captures the 'myClass' instance, which in turn owns the promise. This cycle is not broken until the promise is resolved. ```swift myClass.doSomething().then { string in myClass.doSomeOtherThing() } ``` -------------------------------- ### Create Promise with Synchronous Work (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Use the 'do' operator for promise work blocks that do not require asynchronous fulfillment. The block is called asynchronously on the default queue. ```swift let promise = Promise { () -> String in // Called asynchronously on the default queue. guard success else { throw someError } return "Hello world" } ``` -------------------------------- ### Wait for Promises in Objective-C Unit Tests Source: https://github.com/google/promises/blob/master/g3doc/index.md Utilize `FBLWaitForPromisesWithTimeout` to synchronize test execution with asynchronous promise resolutions in Objective-C. Ensure all promises are settled within the specified timeout. ```objectivec #import "path/to/Promises/FBLPromise+Testing.h" // ... - (void)testExample { // Arrange & Act. FBLPromise *promise = [FBLPromise do:^id { return @42; }]; // Assert. XCTAssert(FBLWaitForPromisesWithTimeout(1)); XCTAssertEqualObjects(promise.value, @42); XCTAssertNil(promise.error); } // ... ``` -------------------------------- ### Explicit Return Type for Multi-Expression Closure (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Demonstrates how to explicitly declare the return type for a Swift closure containing multiple expressions to resolve the 'Unexpected non-void return value in void function' error. ```swift .then { number -> String in print("five") return "five" } ``` -------------------------------- ### Set Default Dispatch Queue (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Sets the global dispatch queue as the default for all Promise operations. Use this when the main queue is busy with a custom run loop. ```swift DispatchQueue.promises = .global() ``` -------------------------------- ### Explicit Return Type for Single Expression Closure (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Shows how to explicitly state the return type for a Swift closure when it contains only a single expression, to avoid compiler errors. ```swift .then { number in return 5 } ``` -------------------------------- ### Recover from Errors in Promise Chain Source: https://github.com/google/promises/blob/master/g3doc/index.md Use the recover method to catch an error and provide a fallback mechanism without breaking the promise chain. This allows for graceful error handling and alternative data fetching. ```swift getCurrentUserContactsAvatars().recover { error in print("Fallback to default avatars due to error: \(error)") return self.getDefaultsAvatars() }.then { avatars in self.update(avatars) } ``` ```objectivec [[[self getCurrentUserContactsAvatars] recover:^id(NSError *error) { NSLog(@"Fallback to default avatars due to error: %@", error); return [self getDefaultsAvatars]; }] then:^id(NSArray *avatars) { [self updateAvatars:avatars]; return avatars; }]; ``` -------------------------------- ### Validate Promise Value (Objective-C) Source: https://github.com/google/promises/blob/master/g3doc/index.md Performs value checks within a promise chain. Rejects with validation failure if the predicate returns false. ```objectivec [[[[self getAuthToken] validate:^BOOL(NSString *authToken) { return authToken.length > 0; }] then:^id(NSString *authToken) { return [self getDataWithToken:authToken]; }] catch:^(NSError *error) { NSLog(@"Failed to get auth token: %@", error); }]; ``` -------------------------------- ### Wait for Promises in Swift Unit Tests Source: https://github.com/google/promises/blob/master/g3doc/index.md Use `waitForPromises` to ensure all asynchronous operations complete before asserting test results. This is crucial for single-threaded test environments. ```swift @testable import Promises // ... func testExample() { // Arrange & Act. let promise = Promise { 42 } // Assert. XCTAssert(waitForPromises(timeout: 1)) XCTAssertEqual(promise.value, 42) XCTAssertNil(promise.error) } // ... ``` -------------------------------- ### Catching Errors in Objective-C Source: https://github.com/google/promises/blob/master/g3doc/index.md Use the `catch` operator to handle errors when an Objective-C Promise is rejected. The provided block receives the `NSError` object. ```objectivec [[self numberFromString:@"abc"] catch:^(NSError *error) { NSLog(@"Cannot convert string to number: %@", error); }]; ``` -------------------------------- ### Swift: Any with Same Type Promises Source: https://github.com/google/promises/blob/master/g3doc/index.md Use 'any' to process an array of promises of the same type. The result is an array of 'Maybe' enums, each containing either a value or an error. ```swift // Promises of same type: any(contacts.map { MyClient.getAvatarFor(contact: $0) }).then { avatarsOrErrors in self.updateAvatars(avatarsOrErrors.flatMap { $0.value }) } ``` -------------------------------- ### Synchronously Wait for Promise Resolution with awaitPromise Source: https://github.com/google/promises/blob/master/g3doc/index.md Use awaitPromise to synchronously wait for a promise to resolve on a different thread. This is useful for complex asynchronous logic that cannot be chained easily. It's generally safer to use awaitPromise from a global concurrent queue to avoid deadlocks. ```swift Promise { let minusFive = try awaitPromise(calculator.negate(5)) let twentyFive = try awaitPromise(calculator.multiply(minusFive, minusFive)) let twenty = try awaitPromise(calculator.add(twentyFive, minusFive)) let five = try awaitPromise(calculator.subtract(twentyFive, twenty)) let zero = try awaitPromise(calculator.add(minusFive, five)) return try awaitPromise(calculator.multiply(zero, five)) }.then { result in // ... }.catch { error in // ... } ``` ```swift Promise(on: .global()) { try awaitPromise(object.someAsyncRoutine()) } ``` -------------------------------- ### Refactor Nested Promises into Separate Method (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Presents a refactoring technique in Swift where nested promise logic is moved to a separate method to improve readability. ```swift loadSomething().then { something in self.loadAnother(with: something) } func loadAnother(with something: Data) -> Promise { loadAnother().then { another in self.doSomething(with: something, and: another) } } ``` -------------------------------- ### Catching Errors in Swift Source: https://github.com/google/promises/blob/master/g3doc/index.md Use the `catch` operator to handle errors when a Swift Promise is rejected. The provided closure receives the error object. ```swift number(from: "abc").catch { error in print("Cannot convert string to number: \(error)") } ``` -------------------------------- ### Reduce Collection of Promises to a Single Value Source: https://github.com/google/promises/blob/master/g3doc/index.md Use Promise.reduce to efficiently produce a single value from a collection of promises using a provided closure. This simplifies combining asynchronous results compared to standard reduce operations. ```swift let numbers = [1, 2, 3] Promise("0").reduce(numbers) { partialString, nextNumber in Promise(partialString + ", " + String(nextNumber)) }.then { string in // Final result = 0, 1, 2, 3 print("Final result = \(string)") } ``` ```objectivec NSArray *numbers = @[ @1, @2, @3 ]; [[[FBLPromise resolvedWith:@"0"] reduce:numbers combine:^id(NSString *partialString, NSNumber *nextNumber) { return [NSString stringWithFormat:@"%@, %@", partialString, nextNumber.stringValue]; }] then:^id(NSString *string) { // Final result = 0, 1, 2, 3 NSLog(@"Final result = %@", string); return nil; }]; ``` -------------------------------- ### Validate Promise Value (Swift) Source: https://github.com/google/promises/blob/master/g3doc/index.md Performs value checks within a promise chain. Rejects with validation failure if the predicate returns false. ```swift getAuthToken().validate { !$0.isEmpty }.then(getData).catch { error in print("Failed to get auth token: \(error)) } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.