Search code examples
iosswiftpromisekit

I would like to implement promises my own, but I could not find the solution


Here I would like to implement 'Promise' like blocks. But I'm not able to set the result for the blocks.

Here I have 2 Challenges :

  1. I'm trying to implement simple Promise example for getting a full string from the first name and last name.
  2. I would like to call 'then' multiple times.
    • First I want to get the full name from both.
    • Then convert into Uppercase.
    • Then convert into lowercase. ..so on (mean to say multiple 'then' conditions with some task.)

How can I achieve multiple times?

Here is my example.

class Promise<T> {

    private var resultHandler : ((_ result:T)->())?
    private var errorHandler :  ((_ error:String)->())?
    private var final : (()->())?

    func resolve(_ value: T) {
        resultHandler?(value)
        final?()
    }

    func reject(_ value: String) {
        errorHandler?(value)
        final?()
    }

    func then(_ block:@escaping (_ result:T)->()) {
        resultHandler = block
    }

    func error(_ block:@escaping (_ result:String)->()) {
        errorHandler = block
    }

    func finally(_ block:@escaping ()->()) {
        final = block
    }

}

func getFullName(firstname: String, lastname: String) -> Promise<String> {
    let p = Promise<String>()

    if firstname.count > 0 && lastname.count > 0 {
        let name = firstname + " "  + lastname
        p.resolve(name)
    }
    else {
        print("--")
            p.reject("Firstname and Lastname can't be empty" )
    }
    return p
}



let p = getFullName(firstname: "Alen", lastname: "Stel")
p.then { (name) in
    print("Name", name)
}

Solution

  • First, to chain things like then, you need to chain the handlers, for example:

    func then(block: @escaping (T)->()) {
        if let oldHandler = resultHandler {
            resultHandler = {
                oldHandler($0)
                block($0)
            }
        } else {
            resultHandler = block
        }
    }
    

    Or you can simplify things by making resultHandler non-optional:

    private var resultHandler: (T)->() = {}
    ...
    func then(block: @escaping (T)->()) {
        resultHandler = { [oldHandler] in
            oldHandler($0)
            block($0)
        }
    }
    

    You can do similar things to error and finally if you like.

    To your existing code, you're attaching then after the Promise is resolved. You have to manage that case. You can do that with a enum State (like .pending, .resolved, .error) or just using some variables like:

    private var value: T?
    ...
    func then(block: @escaping (T)->()) {
        if let value = value {
            block(value)
        } else {
            resultHandler = { [oldHandler] in
                oldHandler($0)
                block($0)
            }
        }
    
     func resolve(_ value: T) {
        self.value = value
        resultHandler(value)
        resultHandler = {}
        final()
        final = {}
    }
    

    (Or something along those lines. I haven't completely tested this.)

    Keep in mind that this is all thread-unsafe, so you have to be careful about adding .then clauses or resolving on different queues, but that can be fine in a simple Promise type as long as you keep that in mind (and makes it dramatically simpler....)