@escape, Trailing closure, completion handlers

Последнее обновление 15 мая 2017 г. | Swift 3.1

В любом случае, давайте изучим замыкания. На первом уроке вы узнали, что замыкания и функции подобны братьям и сестрам. Они идентичны под капотом (ДНК), хотя выглядят немного иначе. Вы также узнали, что можете передавать замыкания / функции в качестве аргументов / параметров и возвращать их. Пока что вы заложили отличную основу для построения прочной башни - изучая реактивное / функциональное программирование на Swift.

Мотивация

Что ж, слишком многие разработчики iOS (в основном я) просто запоминают и копируют из Stack Overflow, когда мы видим такие слова, как обработчики завершения. Это часто происходит, когда вы пытаетесь использовать анимацию, получать данные из сторонних API и т. Д. Поэтому этот учебник написан для меня, помоложе, как создавать собственные обработчики завершения и объяснять, что они из себя представляют и что, черт возьми, происходит под ними.

Что я думаю ты узнаешь

Значение completion handlers, когда использовать@escaping и trailing closure. Это может быть ошеломляющим, но я постараюсь изо всех сил объяснить эти концепции, используя аналогии и простые, но краткие примеры. Я также поместил некоторые ресурсы и исходный код в конце этого руководства. Начнем, братья, сестры или, если вам не удобно, милые люди.

Трейлинг-закрытие

Я большой любитель выяснять этимологию (имя), чтобы понимать без запоминания. Но давайте поговорим в первую очередь о том, что такое «конечное закрытие».

Что ж, опять же, если бы я объяснил это своей 13-летней сестре, конечные закрытия похожи на ... Черт, я не могу ни о чем думать. Вместо этого давайте просто сравним обычные замыкания и конечные замыкания и посмотрим, что мы можем сделать.

Нормальное закрытие

Давайте создадим функцию, которая добавляет диапазон значений, каждое из которых умножается на 10. Последний аргумент функции принимает замыкание, которое умножает каждый ввод. Итак, вы поместите первый параметр как от 0 до 10, и вы получите 0 + 10 + 20 + 30 +…. 100 = 550

Итак, сначала давайте начнем с создания замыкания, которое принимает входные данные, а затем умножает их на 10. Есть два способа. 1. Замыкание с использованием func или 2. просто сохраните его как значение прямо (обложка в Части 1).

// Global Closure (a.k.a function) 
func timesTenFunc(number: Int) -> Int { return number * 10 }
// Normal Closure 
var timesTenClosure: (Int) -> Int = { $0 * 10 }
// Test👆
timesTenFunc(number: 10) // 100
timesTenClosure(10) // 100

Хорошо, теперь пора создать функцию, которая суммирует диапазон значений. Конечно, мы собираемся добавить timesTenFunc или timesTenClosure в качестве последнего параметра. (Пример взят из документа Swift)

func sum(from: Int, to: Int, closure: (Int) -> (Int)) -> Int {
 var sum = 0
 for i in from...to {
  sum += closure(i)
 }
 return sum
}

Теперь, если я попытаюсь запустить это

sum(from: 0, to: 10, closure: timesTenFunc) // 550
sum(from: 0, to: 10, closure: timesTenClosure) // 550 

Или, если вы хотите вставить последний параметр прямо,

// Longer Version
sum(from: 0, to: 10, closure: { number in return number * 10 })
// Shorter Version
sum(from: 0, to: 10, closure: { $0 * 10 })

Скользящие закрытия

Теперь давайте посмотрим, как заново изобрести наш пример, используя замыкающее замыкание. Причина, по которой я подробно остановился на предыдущем примере, заключалась в том, чтобы повторить, как работают замыкания, потому что я не хотел быстро перегружать своих читателей от 0 до 100.

Как и в приведенном выше примере sum, завершающее замыкание можно использовать только в том случае, если функция требует замыкания в качестве последнего аргумента / параметра. Вы можете проследить (проследить) раздел параметров аргумента закрытия. Другими словами, последний параметр отделяется от обычного функционального блока параметров.

// Trailing Closure Longer Version
sum(from: 0, to: 10) { (number) in
 return number * 10 
}
// Trailing Closure Shorter Version
sum(from: 0, to: 10) { return $0 * 10}
// Trailing Closure Extremely Short Version
sum(from: 0, to: 10) { $0 * 10 } 

Итак, в чем преимущество использования скользящих замыканий? Что ж, это особенно полезно, когда ваше выражение закрытия длиннее, чем просто умножение значений, или когда вы используете обработчики завершения, о которых я скоро расскажу в этой статье. Завершающие замыкания делают код удобочитаемым и понятным для глаз, поскольку ясно указывают на то, что это другое животное.

Чтобы прояснить ситуацию, вы можете использовать обычное закрытие внутри функции. Завершающее замыкание необязательно, но большинство разработчиков любят / используют его.

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

Я: Если вы что-то убрали, пожалуйста, поймите эту концепцию.

Бывают случаи, когда вы помещаете закрытие в качестве одного из параметров, но вы хотите выполнить закрытие только после возврата из функции. Например, что, если вы хотите напечатать «Hello, world» только после того, как вы полностью переключились на следующий ViewController?

Если нормальные случаи, вы увидите

self.present(nextViewController, animated: true, completion: nil)

Но, чтобы напечатать «Hello world», только после того, как будет представлен nextViewController,

self.present(nextViewController, animated: true, completion: {
 print("Hello World") 
})

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