Страх медленно начал проявляться, когда я понял, что у меня заканчиваются эти стоковые фотографии.

Swift + инициализация с замыканиями

Закрытие F.T.W.

Небольшое примечание - все мои будущие посты будут опубликованы на моем специальном сайте, и эта публикация больше не обновляется. Спасибо за прочтение!

Я начинаю по-настоящему копать весь танец инициализации в Swift. Я написал об этом. Я написал о том, почему это работает так, как работает. Я поговорил об этом. Я читал об этом (много). Но эй, я вернулся для еще одного акта по этому вопросу.

Из всех многочисленных, красивых и разнообразных способов можно что-то инициализировать в Swift - использование замыканий обычно не рассматривается как метод для этого. Но, увы, он может сделать код initp (2) намного менее болезненным и немного более управляемым.

Для разработчиков программного интерфейса - это для вас !

UIKit == UIHugeSetupCode ()

Смотри, это не вина UIKits. Компоненты, с которыми пользователь должен взаимодействовать, поддаются огромному количеству кода настройки, потому что предпочтения. Как правило, многое из этого находится в viewDidLoad или loadView:

переопределить функцию loadView ()
{
    let helloWorldLbl = UILabel ()
    helloWorldLbl.text = NSLocalizedString («controller.topLbl.helloWorld», комментарий: «Привет, мир!»)
    helloWorldLbl.font = UIFont.preferredFontForTextStyle (UIFontTextStyleBody)
    helloWorldLbl.textColor = UIColor.whiteColor ()
    helloWorldLbl.textAlignment = .Center
    self.view.addSubview (helloWorldLbl)
}

Это довольно стандартно для тех из нас, кто рискует в аквариуме Cocoa Touch без .xib или .storyboard. Хотя, если вы поделитесь моей любовью к мельчайшим методам viewDidLoad или loadView, вы можете отложить это в другом месте.

Скажем, собственность:

let helloWorldLbl: UILabel = {
    let lbl = UILabel ()
    lbl.text = NSLocalizedString («controller.topLbl.helloWorld», комментарий: «Hello World!»)
    lbl.font = UIFont.preferredFontForTextStyle (UIFontTextStyleBody)
    lbl.textColor = UIColor.whiteColor ()
    lbl.textAlignment = .Center
    возврат фунтов
} ()

Милая. В собственной книге Apple по Swift, он отмечает, что «если значение по умолчанию вашего свойства требует некоторой настройки или настройки, вы можете использовать закрытие или глобальную функцию для предоставления настраиваемого значения по умолчанию для этого свойства». Как мы только что упомянули, элементы управления UIKit дают много настроек и настроек.

Однако один из приятных побочных продуктов заключается в том, как выглядит loadView:

переопределить функцию loadView
{
    self.view.addSubview (self.helloWorldLbl)
}

Обратите внимание, однако, на «()» в конце закрытия в объявлении свойства. Это позволяет маленьким мастерам Swift, которые компилируют ваш код, знать, что экземпляр присваивается возвращаемому типу замыкания. Если бы мы пропустили это, возможно, мы могли бы назначить фактическое закрытие самого экземпляра.

И в этом случае это .

Правила есть Правила

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

Например:

let helloWorldLbl: UILabel = {
    let lbl = UILabel ()
    lbl.text = self.someFunctionToDetermineText () // Ошибка компилятора
    lbl.font = UIFont.preferredFontForTextStyle (UIFontTextStyleBody)
    lbl.textColor = self.myAppTheme.textColor () // Еще одна ошибка
    lbl.textAlignment = .Center
    возврат фунтов
} ()

Экземпляр self может быть еще небезопасным для использования, или он может не пройти двухфазный процесс инициализации Swift. То же самое действительно для любых свойств экземпляра, которые могут быть или не быть выделены и инициализированы, так как замыкание выполняется немедленно.

Это явный, но оправданный недостаток с использованием замыканий для инициализации. Это имеет смысл, хотя и соответствует одной из трех целей Swift: безопасность.

Получай милые с коллекциями

Одна из областей, где я нашел эту технику особенно полезной, - это экземпляры, представляющие одну из множества различных форм коллекции в Swift. Из многих талантов Свифта нарезка и просеивание коллекций с силой тысячи титанов является одной из моих самых любимых.

Рассмотрим следующий пример, взятый из инициализатора в проекте, над которым я сейчас работаю. Класс, в котором находится этот код, имеет свойство [Developer]. При новом запуске я установил их начальные значения из файла .plist. После этого они сохраняются через NSKeyedArchiver.

guard пусть devs = NSKeyedUnarchiver.unarchiveObjectWithFile (DevDataManager.ArchiveURL.path!) как? [Разработчик] еще
{
    self.developers = {
        let pListData = // Получить данные списка
        var devArray: [Developer] = [Developer] ()
        // Установить devArray из данных plist
        return devArray.map {$ 0.setLocation ()}
                       .filter {$ 0.isRentable}
                       .sort {$ 0.name <$ 1.name}
     } ()
    вернуть
}
self.developers = devs

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

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

Получение NSCute

Если вы просто действительно копаете инициализацию с замыканием, но страдаете от серьезного недостатка использования этих функциональных $ в вашем коде, поднимите настроение. Используя некоторый адепт Swiftery, можно создать некоторый код, который выводит тип внутри самого замыкания, что дает некоторую конфигурацию в профессиональном стиле. Рассмотрим этот код, который я впервые наткнулся на всегда информативный NSHipster:

@warn_unused_result
public func Init  (значение: Type, @noescape block: (object: Type) -> Void) -> Type
{
    блок (объект: значение)
    возвращаемое значение
}

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

let helloWorldLbl = Init (UILabel ()) {
    $ 0.text = NSLocalizedString («controller.topLbl.helloWorld», комментарий: «Привет, мир!»)
    $ 0.font = UIFont.preferredFontForTextStyle (UIFontTextStyleBody)
    $ 0.textColor = UIColor.whiteColor ()
    $ 0.textAlignment = .Center
}

Хотя это может показаться причудливым, он действительно устраняет необходимость в переменной экземпляра из замыкания и избавляет от требования «()». Очень мило .

Последние мысли

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

Это забавный способ добиться цели, и у нашего старого друга Objective-C есть даже несколько способов сделать то же самое. Но эй, чем больше ты знаешь, амирит?

До следующей недели = {пусть неделя = неделя () week.advancedBy (дней: 7)} ()

Джордан Морган (Jordan Morgan) - инженер-программист iOS, который работает в Dreaming In Binary

Если вы узнали об использовании замыканий для инициализаторов, пожалуйста, не стесняйтесь и NSRecommend (это, где: ниже);