Xib swift для чего
The New iOS Mobile Enterprise. Часть #1: Кодогенерация для ресурсов
Всем привет!
Меня зовут Дмитрий. Так получилось, что я являюсь тим лидом в команде из 13 iOS разработчиков уже на протяжении двух лет. И вместе мы трудимся над приложением Тинькофф Бизнес.
Хочу поделиться с вами нашим опытом о том, как релизить приложение в неожиданный момент с максимальным набором фич или баг фиксами и при этом не поседеть.
Расскажу о практиках и подходах которые помогли команде заметно ускориться в разработке и тестировании и заметно сократить количество стресса, багов, проблем при внеплановом или срочном релизе. #MakeReleaseWithoutStress.
Поехали!
Описание проблемы
Представьте себе следующую ситуацию.
Идет очередной релиз. Ему предшествовало регрессионное тестирование, тестировщики снова нашли место, в котором вместо текста в приложении отображается ID строки.
Это была одна из самых частых наших проблем с которой мы сталкивались.
Вы можете не столкнуться с данной проблемой, если у вас не локализовано приложение на другой язык, или вся локализация пишется строками прямо в коде без использования Localizable.strings файла.
Но вы можете столкнуться с другими проблемами, которые мы поможем вам решить:
Причина → Следствие
Почему это все происходит?
Есть программный код, который компилируется. Если вы что-то написали не так (синтаксически, или неправильное название функции при вызове), то ваш проект просто не соберется. Это понятно, очевидно и логично.
А как быть с такими вещами, как ресурсы?
Они не компилируются, просто добавляются в bundle уже после компиляции кода. В связи с этим может возникать большое количество проблем в runtime, например, тот случай, что описан выше — со строками в локализации.
Поиск решения
Мы задумались, как подобные проблемы решаются вообще, и как мы можем это исправить. Я вспомнил одну из конференций Cocoaheads в mail.ru. Там был доклад про сравнение инструментов для кодогенерации.
Посмотрев еще раз, что эти инструменты (библиотеки/фреймворки) из себя представляют, мы наконец-то нашли то, что было нужно.
При этом, похожий подход уже годами используется разработчиками под Android. Google подумал о них и сделал им такой инструмент из коробки. А ведь нам Apple даже стабильный Xcode не может сделать.
Оставалось выяснить только одно — какой именно инструмент выбрать: Natalie, SwiftGen или R.swift?
У Natalie не было поддержки локализации, от него было решено сразу отказаться. У SwiftGen и R.swift были очень похожие возможности. Мы сделали выбор в пользу R.swift, просто исходя из количества звезд, зная о том, что в любой момент мы можем поменять на SwiftGen.
Как работает R.swift
Файл имеет следующую структуру:
Применение в реальных условиях
Небольшое пояснение контента ниже:
*Было — пользовались подходом какое-то время, в итоге, ушли от него
*Стало — подход который используем при написании нового кода
*Не было, но у вас может быть — подход, которого никогда не существовало в нашем приложении, но я встречал его в различных проектах, в те далекие времена, когда еще не работал в Tinkoff.ru.
Localization
Мы начали применять R.swift для локализации, это избавило нас от проблем, о которых мы писали в самом начале. Теперь, если поменялся id в локализации, то проект не соберется.
*Это работает только при условии, если вы поменяли id во всех локализациях на другой. Если же в какой-то из локализаций осталась строка, то при компиляции будет warning, что данный id локализован не на всех языках.
Правильная передача данных
Правильная передача данных
Доброго времени суток, друзья!
Сегодня мы рассмотрим передачу данных между ViewControllers. На самом деле передача данных между ViewControllers может показаться тривиальной задачей, но если учесть, что любое реальное приложение для iOS будет иметь много ViewControllers, то коммуникация становится их важной частью. Неправильное понимание этого может привести к трудному исправлению ошибок.
В целом существует много способов сделать это, но лишь некоторые из них являются лучшей практикой.
В этой статье я покажу вам такие практики передачи данных:
Передача данных вперед
Передача данных происходит каждый раз, когда на экране появляется новый ViewController.
Это может произойти через segue или программно.
Передача данных вперед между ViewController с использованием segues
Заметка
Всегда правильно задавайте идентификатор для segue. Хорошей практикой будет называть идентификатор тем, что он делает. Потому что может быть ситуации когда Вам нужно передать 2 и более segue в один контроллер. В дальнейшем это поможет свободно ориентироваться в проекте.
Передача данных вперед между ViewController без segues
Иногда вы можете подключить ViewController программно, а не использовать segue.
И готово! Так как в SecondViewController не поменялся код, показываем код FirstViewController :
Передача данных в обратном направлении
Передача данных назад в приложении iOS так же важна, как и их перемещение вперед. Пользователи часто возвращаются к предыдущему экрану, который они посетили.
Когда пользователь взаимодействует с вашим приложением, вы должны обновлять эти предыдущие экраны. Это не происходит автоматически, поэтому вы можете использовать разные методы.
Передача данных в обратном направлении через unwind segue
Передача данных в обратном направлении при помощи делегата
Иногда техники, которые Вы видели, все еще недостаточны.
Заметка
Для закрепления можете сами попробовать сделать это, взяв примеры из 1.2 Передача данных вперед между ViewController без segues.
Продвинутые техники
Замена делегирования на замыкания (closures) Swift
Некоторые разработчики используют замыкания ( closures ) Swift для передачи данных назад между ViewControllers. Этот метод похож на делегирование, но более гибкий. Это также причина, почему я обычно рекомендую не использовать его.
И теперь в FirstViewController также устанавливает связь с этим замыканием, когда происходит переход. Но в этом случае вместо передачи ссылки на себя, он передает замыкание.
Также обратите внимание, что замыкание содержит ссылку на себя. Таким образом, как и делегирование, использование замыканий по-прежнему создает связь между двумя ViewController.
Этот подход немного более лаконичен, чем делегирование. Но использование замыканий также имеет ряд особенностей / недостатков, которых нет у делегирования.
Если вам нужно более одного замыкания для связи с предыдущим контроллером представления, вам нужно сохранить свойство для каждого из них. При делегировании весь интерфейс выделяется внутри протокола, и вам нужно только одно свойство делегата.
На мой взгляд, замыкания лучше работают как обратные вызовы для асинхронных задач, таких как сетевые запросы или анимации. Делегирование является лучшим решением для связи ViewController.
Неправильные техники
Мы познакомились с одними из лучших практик для передачи данных между ViewController. Но к сожалению, в просторах интернета наблюдается и много неправильных.
В этом разделе мы рассмотрим, какие из них, и почему вы не должны их использовать.
Не используйте UserDefaults iOS
В iOS UserDefaults хранят пользовательские настройки, которые должны сохраняться между запусками приложения.
Кроме того, вы можете хранить только простые типы данных в UserDefaults в форме списков свойств. Это означает, что вам нужно преобразовать любой пользовательский тип, прежде чем вы сможете поместить его туда.
В общем, ваше приложение должно получать доступ к UserDefaults через одну точку, которая обычно является настраиваемым контроллером совместно используемой модели.
Не используйте Notifications
Notifications в iOS дают вам канал, по которому какой-то код может отправлять сообщение другим объектам, на которые он не имеет прямой ссылки.
Я видел, как многие разработчики используют Notifications для передачи данных между контроллерами представления. Это не то, для чего они нужны!
Выводы
Как я и говорил, существует много способов передачи данных между ViewController. Но только некоторые из них можно назвать хорошей практикой. Поначалу другие могут показаться удобными, но потом они могут создать Вам проблемы в будущем.
Поэтому выбирайте правильный подход и двигайтесь дальше!
А в ваших iOS приложениях IBOutlet уже private?
Вы наверняка использовали Storyboard или XIB для верстки интерфейсов? Верстать из кода это прекрасно, но иногда намного проще понять как устроен какой-то из компонентов интерфейса, увидев его, а не прочитав. В этой записи я хочу обсудить необходимость использования для IBOutlet модификатора private.
Разработчиков, для которых инкапсуляция IBOutlet является очевидной, тут вряд ли что-то удивит, зато может быть интересен опрос в конце статьи.
Представим, что вы собираетесь создать IBOutlet (ссылку на View с Storyboard) для какого-нибудь из ваших UILabel. При перетаскивании мышкой Xcode заботливо создаст нам что-то вроде
Я долгое время считал эту конструкцию оптимальной, до того момента как мой коллега не спросил — а почему твои IBOutlet не private?
В самом деле, зачем мне оставлять все IBOutlet-ы доступными извне?
Представим себе классическую задачу — у нас есть ячейка, в которой отображается, к примеру, чей-то контакт
С помощью добавления private к привычным нам IBOutlet можно гарантировать, что указанные поля ячейки не будет заданы из другого класса. Особенно это может быть полезно при командной работе, когда кто-то по неосторожности / нехватке времени / глупости (нужное подчеркнуть) попробует задать цвета, текст или какие-то другие свойства у Label-ов ячейки прямо в методе tableView(_:cellForRowAt:).
А представьте, что ячейка или целый ViewController содержит множество IBOutlet-ов, что настроек отображения масса. Не проще ли обезопасить себя добавлением private, чем потом искать почему внешний вид элемента вдруг изменился или откуда-то появился Gesture Recognizer, который задает неожиданное поведение?
P.S.: Если после прочтения вам захочется использовать private для IBOutlet-ов, то для простоты можно завести для этого снипет в Xcode.
Ниже приведен опрос, если вы захотите прокомментировать свой вариант ответа, welcome в комментарии.