Существует массив с неопределенным количеством замыканий, как их вкладывать? - PullRequest
0 голосов
/ 12 апреля 2019

Вот упрощенный сценарий:

Что я делаю, это вкладываю их вручную. Есть ли элегантная реализация?

class Handler {
    func process(_ result: String, done: @escaping (String) -> Void) {
        DispatchQueue.global().async {  // do sth
            done("do something async")
        }
    }
}

func intercept(result: String, with handlers: [Handler], callback: @escaping (String) -> Void) {
    switch handlers.count {
    case 1:
        handlers[0].process(result) { r1 in
            callback(r1)
        }
    case 2:
        handlers[0].process(result) { r1 in
            handlers[1].process(r1) { r2 in
                callback(r2)
            }
        }
    // ... maybe up to 5
    default:
        callback(result)
    }
}

1 Ответ

3 голосов
/ 12 апреля 2019

Как насчет использования рекурсивных вызовов:

func intercept2(result: String, with handlers: [Handler], callback: @escaping (String) -> Void) {

    if handlers.isEmpty {
        callback(result)
    } else {
        handlers[0].process(result) { (r) in
            intercept2(result: r, with: Array(handlers.dropFirst()), callback: callback)
        }
    }
}

Потому что вы хотите позвонить intercept() с остальными handlers, кроме первого.

С образцами испытаний:

class Handler {
    func process(_ result: String, done: @escaping (String) -> Void) {
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5) {
            let retVal = result + "-"
            print("process retVal: \(retVal)")
            done(retVal)
        }
    }
}

func intercept(result: String, with handlers: [Handler], callback: @escaping (String) -> Void) {
    switch handlers.count {
    case 1:
        handlers[0].process(result) { r1 in
            callback(r1)
        }
    case 2:
        handlers[0].process(result) { r1 in
            handlers[1].process(r1) { r2 in
                callback(r2)
            }
        }
    case 3:
        handlers[0].process(result) { r1 in
            handlers[1].process(r1) { r2 in
                handlers[2].process(r2) { (r3) in
                    callback(r3)
                }
            }
        }
    // ... maybe up to 5
    default:
        callback(result)
    }
}


func intercept2(result: String, with handlers: [Handler], callback: @escaping (String) -> Void) {

    if handlers.isEmpty {
        callback(result)
    } else {
        handlers[0].process(result) { (r) in
            intercept2(result: r, with: Array(handlers.dropFirst()), callback: callback)
        }
    }
}

let handlers: [Handler] = [Handler(), Handler(), Handler()]

let initialOne = "String-"
intercept(result: initialOne, with: handlers) { (res1) in
    print("Result Interecept1 : \(res1)")
    intercept2(result: initialOne, with: handlers) { (res2) in
        print("Result Interecept2 : \(res2)")
        print("res1 \(res1 == res2 ? "=" : "!")= res2")
    }
}

Я поместил два теста внутри другого, чтобы убедиться, что первые отпечатки для исходного, а секунды для рекурсивного.

Выход:

$>process retVal: String--
$>process retVal: String---
$>process retVal: String----
$>Result Interecept1 : String----
$>process retVal: String--
$>process retVal: String---
$>process retVal: String----
$>Result Interecept2 : String----
$>res1 == res2
...