Swift — цепочка методов

Я хотел бы реализовать цепочку методов в моем swift коде, вероятно, для Alamofire методов. Например, если мне нужно использовать мою функцию, как показано ниже

getListForID(12).Success {
   // Success block
}. Failure {
   // Failure block
}

Как мне создать функцию getListForID?


person iOS    schedule 09.05.2016    source источник
comment
Вы можете вернуть объект, который имеет свойства success и failure, и сеттер success также возвращает это, кстати, вы можете использовать promiseKit, который делает это promisekit. организация   -  person Daniel Krom    schedule 09.05.2016
comment
Вы можете попробовать мою статью, которая делает именно это: Связывание асинхронных функций в Swift.   -  person zeitgeist7    schedule 11.08.2017


Ответы (2)


Чтобы расширить основные моменты @dasblinkenlight и @Sulthan — вот небольшой пример того, как вы можете заставить свою функцию запроса выполнять успешное и неудачное закрытие в удобном синтаксисе, который вам нужен.

Во-первых, вам нужно определить новый класс для представления «обработчика результатов». Это то, что будут передавать ваши функции success и failure, что позволит вам добавить несколько завершающих замыканий, чтобы составить логику вашего блока завершения. Вы хотите, чтобы это выглядело примерно так:

class ResultHandler {

    typealias SuccessClosure = RequestHandler.Output->Void
    typealias FailureClosure = Void->Void

    // the success and failure callback arrays
    private var _successes = [SuccessClosure]()
    private var _failures = [FailureClosure]()

    /// Invoke all the stored callbacks with a given callback result
    func invokeCallbacks(result:RequestHandler.Result) {

        switch result {
            case .Success(let output): _successes.forEach{$0(output)}
            case .Failure: _failures.forEach{$0()}
        }
    }

    // remove all callbacks – could call this from within invokeCallbacks
    // depending on the re-usability of the class
    func removeAllCallbacks() {
        _successes.removeAll()
        _failures.removeAll()
    }

    /// appends a new success callback to the result handler's successes array
    func success(closure:SuccessClosure) -> Self {
        _successes.append(closure)
        return self
    }

    /// appends a new failure callback to the result handler's failures array
    func failure(closure:FailureClosure) -> Self {
        _failures.append(closure)
        return self
    }
}

Это позволит вам определить несколько успешных или неудачных закрытий, которые будут выполняться по завершении. Если вам на самом деле не нужна емкость для нескольких замыканий, вы можете упростить класс, удалив массивы и вместо этого просто отслеживая последние добавленные блоки успешного и неудачного завершения.

Теперь все, что вам нужно сделать, это определить функцию, которая генерирует новый экземпляр ResultHandler, а затем выполняет заданный асинхронный запрос с вызовом метода invokeCallbacks по завершении:

func doRequest(input:Input) -> ResultHandler {
    let resultHandler = ResultHandler()
    doSomethingAsynchronous(resultHandler.invokeCallbacks)
    return resultHandler
}

Теперь вы можете назвать это так:

doRequest(input).success {result in
    print("success, with:", result)
}.failure {
    print("fail :(")
}

Единственное, что следует отметить, это то, что ваша функция doSomethingAsynchronous должна будет отправить свой блок завершения обратно в основной поток, чтобы обеспечить потокобезопасность.


Полный проект (с добавленным примером использования): https://github.com/hamishknight/Callback-Closure-Chaining

person Hamish    schedule 09.05.2016

Чтобы понять, что происходит, было бы полезно переписать код без «удобного» синтаксиса, который позволяет опускать круглые скобки, когда замыкание является последним параметром функции:

getListForID(12)
    .Success( { /* Success block */ } )
    .Failure( { /* Failure block */ } )

Это делает структуру кода этого API более понятной:

  • Возвращаемое значение getListForID должно быть объектом
  • Объект должен иметь две функции с именами Success и Failure*
  • И Success, и Failure должны принимать один параметр типа замыкания.
  • Оба Success и Failure должны вернуть self

* Объект может иметь только функцию Success и возвращать другой объект с одной функцией Failure, но тогда вы не сможете переупорядочить обработчики Success и Failure или вообще удалить обработчик Success .

person Sergey Kalinichenko    schedule 09.05.2016
comment
Кроме того, одной из возможных реализаций является простая оболочка для двух массивов — одного массива обработчиков успеха и одного массива обработчиков ошибок, когда методы Success и Failure просто добавляют параметр в заданный массив. - person Sulthan; 09.05.2016
comment
@Султан Абсолютно! Я попытался объяснить синтаксис, не вдаваясь в подробности того, что происходит внутри методов Success и Failure. Оба метода будут принимать замыкание в качестве аргумента; что делать с этими замыканиями, зависит от реализации метода, хотя хранение замыканий в отдельных массивах для будущего использования имеет смысл. - person Sergey Kalinichenko; 09.05.2016