Swift @escaping и обработчик завершения



[Swift]



Привет, я пытаюсь понять "закрытие" Swift более точно.



Но @escaping и Completion Handler слишком трудно понять



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

Это кодовый пример официальных документов



var completionHandlers: [()->Void] = []

func someFunctionWithEscapingClosure(completionHandler: @escaping ()->Void){
completionHandlers.append(completionHandler)
}
func someFunctionWithNoneescapingClosure(closure: ()->Void){
closure()
}

class SomeClass{
var x:Int = 10
func doSomething(){
someFunctionWithEscapingClosure {
self.x = 100
//not excute yet
}
someFunctionWithNoneescapingClosure {
x = 200
}
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x)

completionHandlers.first?()
print(instance.x)


Я слышал, что есть два способа и причины использования @escaping



Первый предназначен для хранения закрытия, второй-для асинхронной работы цели.



Ниже приведены мои вопросы :



Во-первых, если doSomething выполняется, то someFunctionWithEscapingClosure будет выполняться с параметром closure, и это закрытие будет сохранено в массиве глобальных переменных.



Я думаю, что закрытие-это {самость.x = 100}

Как self в {самости.x = 100} что сохраненное в глобальной переменной completionHandlers может соединиться с instance тем объектом SomeClass ?



Во-вторых, я понимаю someFunctionWithEscapingClosure Вот так.

Для хранения замыкания локальной переменной completionHandler в глобальная переменная 'completionHandlerswe using@escaping` ключевое слово!



Без @escaping ключевого слова someFunctionWithEscapingClosure возвращает, локальная переменная completionHandler удалит из памяти



@escaping это держать это замыкание в памяти



Правильно ли это?



Наконец, я просто задаюсь вопросом о существовании этой грамматики.

Возможно, это очень рудиментарный вопрос.

Если мы хотим, чтобы некоторая функция выполнялась после некоторой конкретной функции. Почему бы нам просто не вызвать какую-нибудь функцию после a конкретный вызов функции?



В чем разница между использованием вышеупомянутого шаблона и использованием экранирующей функции обратного вызова?



Спасибо за чтение длинных вопросов и извините за то, что я не родной

1023   2  

2 ответов:

Прежде всего, я хочу сказать: "очень хороший вопрос :)"

Обработчик Завершения:

Предположим, что пользователь обновляет приложение во время его использования. Вы определенно хотите уведомить пользователя, когда это будет сделано. Возможно, вы захотите открыть коробку с надписью: "Поздравляю, теперь вы можете полностью наслаждаться!"

Итак, как вы запускаете блок кода только после завершения загрузки? Кроме того, как вы анимируете определенные объекты только после того, как контроллер вида был перемещен в следующий? Ну, мы собираемся выяснить, как создать такого, как босс. Основываясь на моем обширном списке словаря, обработчики завершения обозначают

Делайте что-нибудь, когда все уже сделано

Для получения более подробной информации, пожалуйста, посетите этот пост в блоге.

Эта ссылка дает мне полную ясность о обработчиках завершения (с точки зрения разработчика она точно определяет, что нам нужно понять).

@экранирующие замыкания:

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

Существует несколько способов избежать замыкания в содержащей функции:

  • Хранение: когда вам нужно сохранить закрытие в глобальной переменной, свойстве или любом другом хранилище, которое существует в памяти прошлого объекта. вызов функции выполняется и возвращает компилятор обратно.

  • Асинхронное выполнение: когда вы выполняете закрытие асинхронно на очереди отправки, очередь будет держать закрытие в памяти для вас, может быть использована в будущем. В этом случае вы понятия не имеете, когда будет выполнено закрытие.

При попытке использовать закрытие в этих сценариях компилятор Swift покажет ошибку:

скриншот ошибки

Для большей ясности в этой теме вы можете проверить этот пост на Medium .

Я надеюсь, что вы получите хорошее понимание из этой ссылки.

Если у вас все еще есть какие-либо вопросы (но обязательно прочтите эту ссылку строка за строкой; это очень хорошо объяснено), то не стесняйтесь поделиться своим комментарием.

Спасибо, продолжайте публиковать, если этот ответ нуждается в обновлении

Вот небольшой класс примеров, которые я использую, чтобы напомнить себе, как работает @escaping.

class EscapingExamples: NSObject {

    var closure: (() -> Void)?

    func storageExample(with completion: (() -> Void)) {
        //This will produce a compile time error because `closure` is outside the scope of this
        //function - it's a class-instance level variable - and so it could be called by any other method at
        //any time, even after this function has completed.  We need to tell `completion` that it may remain in memory, i.e. `escape` the scope of this
        //function.
        closure = completion
        //Run some function that may call `closure` at some point, but not necessary for the error to show up.
        //runOperation()
    }

    func asyncExample(with completion: (() -> Void)) {
        //This will produce a compile time error because the completion closure may be called at any time
        //due to the async nature of the call which preceeds/encloses it.  We need to tell `completion` that it should
        //stay in memory, i.e.`escape` the scope of this function.
        DispatchQueue.global().async {
            completion()
        }
    }

    func asyncExample2(with completion: (() -> Void)) {
        //The same as the above method - the compiler sees the `@escaping` nature of the
        //closure required by `anotherThing()` and tells us we need to allow our own completion
        //closure to be @escaping too.  `anotherThing`'s completion block will be retained in memory until
        //it is executed, so our completion closure must explicitely do the same.
        runAsyncTask {
            completion()
        }
    }





    func runAsyncTask(completion: @escaping (() -> Void)) {
        DispatchQueue.global().async {
            completion()
        }
    }

}

Comments

    Ничего не найдено.