google / promises

Promises is a modern framework that provides a synchronization construct for Swift and Objective-C.
Apache License 2.0
3.8k stars 293 forks source link

How to make Promise without returned value? #37

Closed alexanderkhitev closed 6 years ago

alexanderkhitev commented 6 years ago

Hello! Great framework! Please tell me how to do Promise without a return value? For example, I update the user name in firebase and I expect some value, but only check for an error. I now write Bool as a return value, although in fact I do not need it, how can this be done differently?

I would also like to know what is better to fix in this code for a more productive / readable code using the Promise framework. Thanks.

Sample code

    private func updateName(_ name: String) -> Promise<Bool> {
        let promise = Promise<Bool>(on: .global(qos: .default)) { fulfill, reject in
            guard let userID = UserRealmManager().getUser()?.id else {
                // TODO: - make custom error
                return
            }
            let ref = Database.database().reference().child(UsersPaths.Main.users.rawValue).child(userID)
            let data = [UsersPaths.UserProperties.displayName.rawValue : userID]
            ref.updateChildValues(data, withCompletionBlock: { (error, _) in
                if let error = error {
                    reject(error)
                } else {
                    fulfill(true)
                }
            })
        }
        return promise
    }
shoumikhin commented 6 years ago

Hi Alex,

I imagine wrap could work for you?

private func updateName(_ name: String) -> Promise<Type> {
  return wrap(on: .global(qos: .default)) { handler in
    guard let userID = UserRealmManager().getUser()?.id else { throw CustomError }
    let ref = Database.database().reference().child(UsersPaths.Main.users.rawValue).child(userID)
    ref.updateChildValues([UsersPaths.UserProperties.displayName.rawValue : userID], handler)
  }
}

Where the Type of the promise would be the same as whatever the type of updateChildValues completion handler is. You may also need to specify the type of handler for wrap operator explicitly as (handler: @escaping (Type?, Error?) -> Void) to disambiguate between other wrap overloads.

If you'd like to use Void instead of that Type, you can chain another then at the end, like so:

return wrap { handler in
  //...
}.then { _ in () }

Where () constructs and returns an empty tuple, i.e. the value of type Void.

alexanderkhitev commented 6 years ago

Hi @shoumikhin

Thank you very much for your detailed answer.

I make all network logic in the background thread.

richardtop commented 6 years ago

Hi @alexanderkhitev and @shoumikhin, I use Void type for such cases:

Promise<Void> - it works great for cases, when you only need to check for the result:

  @discardableResult func logOut() -> Promise<Void> {
// Clear local storage
    return client.request(EXPIRE_TOKEN_API_ENDPOINT)
  }

// Somewhere in code

loginService.logOut()

or:
loginService.logOut().then .....
shoumikhin commented 6 years ago

Hi @alexanderkhitev,

I've updated the answer above. Since 1.1.0 you can pass an arbitrary dispatch queue to the wrap operator (former resolve) to achieve the behavior you wanted. Let us know if still have any issues, we're happy to help.

Thanks.