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

— Шорткаты и хоткеи
— Навигация
— Редактирование
— Отладка
— Кастомизация
— Сниппеты
— Шаблоны
— Бонус фича
Шорткат — то, что дает быстрый доступ к пункту меню (копировать/вставить/удалить).
Хоткей — то, у чего нет аналога в пункте меню/интерфейсе взаимодействия (кастомный биндинг).
Строгой разницы между этими терминами нет, можно смело использовать их как взаимозаменяемые. Но я постараюсь придерживаться тех определений, которые описал выше.
Примерно полтора года назад мы стали практиковать изучение шорткатов, хоткеев, сниппетов и файловых шаблонов на уровне iOS-команды, чтобы избавиться от рутины. Например, распечатывали листы с расширенными командами (базовые уже знали) и держали их под рукой, чтобы учить. Это вошло в практику и теперь мы тренируем команды во время онбординга (и порой сами узнаем что-то новое).
Использование шорткатов трудно переоценить: попробуйте вспомнить, когда вы последний раз копировали что-либо через контекстное меню (ПКМ -> Копировать). Эти операции делаются на автомате. Давайте рассмотрим, какие еще операции мы можем довести до автоматизма при работе в Xcode.
Базовые клавиши для активации шорткатов:
Базовые шорткаты:
Уверен, большинство из вас знакомы с ними, поэтому перейдём к интересному. Шорткаты разбиты на три блока: навигация, редактирование и отладка.
Начнём автоматизацию рутины с шорткатов для навигации:
? + 0 (ноль) — показать/скрыть панель

? + цифры — быстрое перемещение по вкладкам панели

Повторим трюк с панели навигации для панели

С зажатым option мы также можем пройтись по всем вкладкам панели — ? + ? +цифры:

? + ? + O — быстро найдем и откроем файл. Открыть можно не только файлы проекта, но и файлы с документацией iOS:

Если найденный файл хочется открыть рядом, зажимаем ?, перед тем, как нажать

Либо, можно зажать ? + ? — в этому случае мы сами выбираем, где необходимо расположить радактор:

Перемещаться между редакторами можно с помощью сочетания ? + J + стрелочки для выбора:



Рассмотрим навигацию внутри панели, отображающую путь до файла:

Все взаимодействия с ней происходят путём зажатия ? и цифры.
? + 1 — позволяет узнать о суперклассах нашего класса, какие протоколы он поддерживает, кто вызывает его методы, какие экстеншены есть у класса.

Идем дальше:

? + ? + ? + Enter — открыть класс для сториборда в отдельном редакторе:

? + ?+ ? + ? или ? + ? + ? + ПКМ — контекстное меню иерархии вьюх в сториборде:


Вот что мы сможем делать в итоге:

Все эти сочетания отлично работают с зажатым Shift для выделения. А вот что дальше можно делать с этим выделенным блоком:
? + ?+ [ или ] — перемещает выделенный блок/строчку вверх/вниз. Самая крутая фича здесь — автоматический заход в скоупы.




? + ? + A — показать контекстное меню действий. В зависимости от того, для кого мы вызываем это меню, Xcode предложит релевантные действия. В списке также можно использовать поиск:

Я заметил, что в нашей команде мало кто пользуется шорткатами для консоли, а ведь это не самое редкое место в работе. Давайте изучать.
Брейкпойнты:
Консоль:
Навигация внутри консоли:
В итоге работа с дебагером будет выглядеть примерно вот так:

В настройках Xcode можно задать свои биндинги для операций. Например, зададим хоткей для оборачивания строки в

У себя в команда мы решили что это будет сочетание ^ + ? + L. Можем смело использовать:

Или добавить хоткей для удаления строки целиком — ? + D (? + backspace удаляет только текст):

Возможно не самое очевидное сочетание для такой операции, но использовать удобно:

Можно не только задавать, но и изменять существующие биндинги. Например, зачем мне шорткат для печати в Xcode? Удалил его, теперь можно забиндить на него что-то полезное.
Наша команда на этом не остановилась — а что если забиндить запуск скриптов, например для установки/переустановки подов? В Xcode, в отличие от AppCode, нет встроенного терминала, приходится переключаться между вкладками. Получается, чтобы установить/переустановить поды в проекте, необходимо переключиться на терминал, перейти в папку с проектом и прописать команду. Ужасно долго. Но решение есть!
Воспользуемся другой функциональностью Xcode —

В нашем случае скрипт выглядит так: запускаем терминал (если он не запущен), переходим в папку с проектом и можем указывать нужные команды для работы.
Теперь можно пользоваться терминалом не выходя из Xcode: ? + P запустит скрипт на переустановку. Зажать сочетание — это всё, что от нас нужно.
Какие еще разделы для шорткатов можно прокачать:
Иногда, работая над проектом, я понимал, что раз за разом пишу одно и то же — так называемый бойлерплейт. Этот процесс тоже можно автоматизировать. К счастью, сейчас есть много очень хороших решений и они скорей всего вам знакомы: это и Sourcery для генерации кода по шаблону и библиотеки по типу R.Swift для генерации доступа к ресурсам, и другие фреймворки. Но не всегда есть возможность затащить стороннюю зависимость в проект. К тому же есть бойлерплейт-код, где подобные библиотеки не помогут. Зато поможет стандартный инструмент Xcode — сниппеты.
Сниппеты есть для всех ключевых слов языка Swift (и некоторых других) и стандартных конструкций: циклов, ветвлений, функций. Но часто мне нужен не просто
Изменить стандартные сниппеты нельзя, зато добавить свой совсем просто: выделяем блок кода и в контекстном меню выбираем «Create Code Snippet». Дальше Xcode предложит его настроить: задать имя, добавить описание, платформу, скоуп вызова, и, конечно же, указать комплишн, по которому будет вызываться наш сниппет:

Вот так быстро можно «сгенерировать» код для минимальной работы таблицы (ещё быстрее можно сделать, если сразу в сниппете задать количество строк и возвращать пустую ячейку).
Так выглядит сниппет в библиотеке Xcode (? + ? + L):

А вот как в два тапа можно сделать импорт целой пачки фреймворков для юнит-тестов:

В проекте «Додо Пиццы» мы пишем тесты с помощью Quick/Nimble. Каждый новый спек начинается с импорта 4–6 фреймворков (минимум), и продолжается телом разного уровня вложенности. Импортировать фреймворки мы уже научились, сделаем это и для тела спеки. Всего пара тапов по клавиатуре и сетап для тестов готов:

Еще один кейс: в нашем проекте для логирования ошибки необходимо описать её в специальном виде: создаем энумку, наследуемся от протокола

Для меня это идеальный кандидат для оптимизации своего времени — пусть сниппет делает все за меня:

А сколько еще таких мест можно улучшить (и всё это бесплатно). Несколько личных примеров кандидатов для сниппета:

Часто типы данных и функции нужно объявлять с явным типом доступа. Это можно можно завернуть в сниппет.


Плавно продолжаем тему кодогенерации кода, но теперь поднимемся на уровень выше - шаблоны файлов.
Шаблоны удобны, но Apple не предоставляет инструменты для их разработки и документации. Но можно сделать все ручками, потому что есть доступ к стандартным шаблонам файлов (и проектов) Xcode. Чтобы их найти, перейдём в каталог по этому пути:
Дальше разместим свои темплейты: создаём папку по пути ниже, её имя будет отображаться в окне Xcode. Я назвал папку Helpers:
Шаблон для Xcode — это каталог, куда входят:
Чтобы создать свой шаблон, скопируем папку со стандартным шаблоном Xcode и изменим его под себя. Например, для создания объекта API реквеста у себя в проекте мы используем определенную структуру, где описываем стандартные для запроса вещи: урл, параметры, заголовки.
Часто нам интересны только пара параметров, но всё остальное мы обязаны прописать (обязанность протокола). Как раз для этого случая я создал шаблон файла, который не только экономит мне время, но и сразу подсказывает где и что дописать.
Вот так может выглядеть
Добавил код в

А вот такое окно мы увидим после выбора шаблона:

Вводим имя для реквеста. В итоге будет создан вот такой файл:

Только посмотрите сколько работы за меня делают шаблоны!
Пара моментов:
Рассмотрим более интересное применение шаблонов — многофайловые шаблоны с возможностью кастомизации при создании (code variants).
В проекте «Додо Пиццы» мы отделяем вью от котроллера. Если это новый контроллер, то создаем под него сториборд/ксиб. Чтобы создать один экран, нужно создать минимум 3 файла: вью, контроллер и сториборд. Помимо этого, контроллер должен быть связан с вью, а сториборд иметь ссылки на вью и контроллер. При этом, мне не всегда нужно создавать файл сториборда (если он уже есть), или файл с вью (если она не нужна). В этой ситуации помогут многофайловые шаблоны с кастомизацией.
В нашем случае нужно будет создать 4 папки для шаблона:
Вот так будет выглядеть иерархия:
Здесь уже привычные файлы с иконкой и конфигурацией, но сами шаблоны хранятся в папках. В зависимости от того, какие параметры мы укажем в Xcode при создании контроллера, выберется нужна папка.
Вот так может выглядеть plist:
А вот что получим в итоге:

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

Сила шаблонов в том, что на уровне создания файла можно конфигурировать, что именно нужно создать. Например, можно создать шаблон для VIPER-модуля и при создании указывать только то, что вам нужно (презентер с интерактором или весь модуль целиком).
Как раньше упоминал, для шаблонов нет официальной документации и инструментов для их создания. Возможности шаблонов «перебираются» энтузиастами на основе стандартных шаблонов Xcode. Но есть одна фича, описание которой я не видел ни в одной статье по шаблонам (возможно, эта будет первой).
Фича в том, что в шаблоне мы можем сконфигурировать текстовое поле так, что оно будет выступать в роли превью для вводимого текста. Например, это можно видеть при создании нового проекта — поле

Потрясающе, ведь теперь я знаю, что мне не нужно дописывать бойлерплейт части
Сделать это просто: в
Выглядит эффектно. Спасибо @ihppie за то, что рассказал про эту фичу.
С помощью простых и стандартных вещей можно избежать рутины и значительно сэкономить не только свое время, но и время команды. Все рассмотренные приемы позволяют фокусироваться на коде, а не взаимодействии с IDE во время его написания.
Код со всеми примерами в репозитории на GitHub.

Оглавление
— Шорткаты и хоткеи
— Навигация
— Редактирование
— Отладка
— Кастомизация
— Сниппеты
— Шаблоны
— Бонус фича
Шорткат или хоткей?
Шорткат — то, что дает быстрый доступ к пункту меню (копировать/вставить/удалить).
Хоткей — то, у чего нет аналога в пункте меню/интерфейсе взаимодействия (кастомный биндинг).
Строгой разницы между этими терминами нет, можно смело использовать их как взаимозаменяемые. Но я постараюсь придерживаться тех определений, которые описал выше.
Примерно полтора года назад мы стали практиковать изучение шорткатов, хоткеев, сниппетов и файловых шаблонов на уровне iOS-команды, чтобы избавиться от рутины. Например, распечатывали листы с расширенными командами (базовые уже знали) и держали их под рукой, чтобы учить. Это вошло в практику и теперь мы тренируем команды во время онбординга (и порой сами узнаем что-то новое).
Использование шорткатов трудно переоценить: попробуйте вспомнить, когда вы последний раз копировали что-либо через контекстное меню (ПКМ -> Копировать). Эти операции делаются на автомате. Давайте рассмотрим, какие еще операции мы можем довести до автоматизма при работе в Xcode.
В этой статье рассмотрим шорткаты для UIKit-flow.
Базовые клавиши для активации шорткатов:
- ? — command;
- ? — option;
- ? — control;
- ? — shift.
Базовые шорткаты:
- ? + B — build;
- ? + R — run;
- ? + U — run unit tests;
- ? +. — stop build/run/run unit tests;
- ? + ? + ? + K — clean build folder.
Уверен, большинство из вас знакомы с ними, поэтому перейдём к интересному. Шорткаты разбиты на три блока: навигация, редактирование и отладка.
Навигация
Начнём автоматизацию рутины с шорткатов для навигации:
? + 0 (ноль) — показать/скрыть панель
Navigator
:
? + цифры — быстрое перемещение по вкладкам панели
Navigator
:
Повторим трюк с панели навигации для панели
Inspectors
и научимся скрывать/показывать её. Просто добавляем option: ? + ? + 0 (ноль):
С зажатым option мы также можем пройтись по всем вкладкам панели — ? + ? +цифры:

Assistant Editor
скрыть не получиться, зато в нём можно делать много крутых штук. ? + ? + O — быстро найдем и откроем файл. Открыть можно не только файлы проекта, но и файлы с документацией iOS:

Если найденный файл хочется открыть рядом, зажимаем ?, перед тем, как нажать
Enter
:
Либо, можно зажать ? + ? — в этому случае мы сами выбираем, где необходимо расположить радактор:

Перемещаться между редакторами можно с помощью сочетания ? + J + стрелочки для выбора:

- ? + ? + T — позволяет открыть несколько редакторов (зажмите столько, сколько нужно);
- ? + ? + ? + T — меняет ориентацию для открываемого редактора (если предыдущий редактор открывался горизонтально, то новый откроется вертикально, и наоборот);
- ? + ? + J — поможет быстро найти файл в структуре проекта.

- ? + T — добавить новую вкладку;
- ? + W — закрыть текущую вкладку;
- ? + ? + \ — посмотреть все вкладки.

Рассмотрим навигацию внутри панели, отображающую путь до файла:

Все взаимодействия с ней происходят путём зажатия ? и цифры.
Для всех сочетаний данной панели (за исключением ? + 1) вы можете использовать поиск: после того как сработал хоткей, начните писать название файла/класса. Так работать с данной панелью гораздо удобнее.
? + 1 — позволяет узнать о суперклассах нашего класса, какие протоколы он поддерживает, кто вызывает его методы, какие экстеншены есть у класса.

- ? + 2 и ? + 3 — отображает список файлов, по которым мы перемещались. Эти сочетания отлично дополняют два других: ? + ? + стрелочки влево/вправо для непосредственной навигации по истории просмотренных файлов назад и вперёд;
- ? + 4 — открывает окно для навигации по структуре проекта (мало чем полезно, на мой взгляд, часто проекты имеют большую вложенность);
- ? + 5 — навигация по файлам внутри директории, в которой открыт текущий файл;
- ? + 6 — навигация по свойствам и методам класса в текущем файле.
Идем дальше:
- ? + L — переход к строке кода;
- ? + курсор на миникарте — показать структуру файла.

? + ? + ? + Enter — открыть класс для сториборда в отдельном редакторе:

? + ?+ ? + ? или ? + ? + ? + ПКМ — контекстное меню иерархии вьюх в сториборде:

Редактирование
- ? + стрелки влево/вправо — позволяют быстро перейти в начало/конец строки;
- ? + стрелки влево/вправо — быстрое перемещение между словами без пробелов;
- Control + стрелки влево/вправо — перемещение между словами в
camelCase
.
Здесь есть хитрость: изначально эта комбинация в macOS переключает рабочие столы, поэтому для работы хоткея в Xcode, его нужно переопределить, либо изменить в System Preferences.

Вот что мы сможем делать в итоге:

Все эти сочетания отлично работают с зажатым Shift для выделения. А вот что дальше можно делать с этим выделенным блоком:
? + ?+ [ или ] — перемещает выделенный блок/строчку вверх/вниз. Самая крутая фича здесь — автоматический заход в скоупы.

- ? + [ или ] — перемещает выделенный блок (строку) влево/вправо;
- ? + I — автоматическое выравнивание выделенного блока (согласно настройкам в Xcode -> Preferences -> Text Editing -> Indentations);
- ? + выделение курсором — такая комбинация создает множественные курсоры. Удобно проставлять атрибут доступа в модельке или добавлять/удалять одинаковые части.

- ? + / — закомментировать/раскомментировать текущую строку;
- ? + ? + E — редактировать выделенную сущность (но не забудьте поправить конструктор, его шорткат не затрагивает).

- ? + F — поиск по файлу;
- ? + ? + F — поиск по проекту;
- ? + ? + F — поиск и замена;
- ? + ? + ? + F — фикс всех ошибок в скоупе (не совсем то, о чем вы подумали, но тоже очень крутая вещь). В данном примере явно указывается модификатор доступа
public
.

? + ? + A — показать контекстное меню действий. В зависимости от того, для кого мы вызываем это меню, Xcode предложит релевантные действия. В списке также можно использовать поиск:

Отладка
Я заметил, что в нашей команде мало кто пользуется шорткатами для консоли, а ведь это не самое редкое место в работе. Давайте изучать.
Брейкпойнты:
- ? + \ — добавить/удалить брейкпойнт;
- ? + Y — отключить (disable) брейкпойнт.
Консоль:
- ? + ? + c — открыть консоль;
- ? + ? + Y — скрыть консоль.
Навигация внутри консоли:
- ? + K — очистить содержимое консоли;
- s — step into (step);
- n — step over (next);
- finish — step out;
- c — continue;
- breakpoint disable — отключить все брейкпойнты.
В итоге работа с дебагером будет выглядеть примерно вот так:

Кастомизация
В настройках Xcode можно задать свои биндинги для операций. Например, зададим хоткей для оборачивания строки в
NSLocalizedString
. Для этого перейдем во вкладку Key Bindings
настроек Xcode и найдем интересующую команду:
У себя в команда мы решили что это будет сочетание ^ + ? + L. Можем смело использовать:

Или добавить хоткей для удаления строки целиком — ? + D (? + backspace удаляет только текст):

Возможно не самое очевидное сочетание для такой операции, но использовать удобно:

Можно не только задавать, но и изменять существующие биндинги. Например, зачем мне шорткат для печати в Xcode? Удалил его, теперь можно забиндить на него что-то полезное.
Xcode позволяет создать несколько биндинг сетов. Можно создать сет и пошарить его в команде, это позволит более эффективно работать в паре. Файлы биндингов расположены здесь: ~/Library/Developer/Xcode/UserData/KeyBindings
Наша команда на этом не остановилась — а что если забиндить запуск скриптов, например для установки/переустановки подов? В Xcode, в отличие от AppCode, нет встроенного терминала, приходится переключаться между вкладками. Получается, чтобы установить/переустановить поды в проекте, необходимо переключиться на терминал, перейти в папку с проектом и прописать команду. Ужасно долго. Но решение есть!
Воспользуемся другой функциональностью Xcode —
Behaviors
:- добавим поведение через + внизу слева;
- зададим хоткей для вызова (как раз один освободился);
- укажем путь до скрипта.

В нашем случае скрипт выглядит так: запускаем терминал (если он не запущен), переходим в папку с проектом и можем указывать нужные команды для работы.
#!/bin/sh
osascript <<END
tell application "Terminal"
if not (exists window 1) then reopen
activate
do script "cd `pwd`;bundle install" in window 1
do script "cd `pwd`;bundle exec pod install" in window 1
end tell
END
Теперь можно пользоваться терминалом не выходя из Xcode: ? + P запустит скрипт на переустановку. Зажать сочетание — это всё, что от нас нужно.
Какие еще разделы для шорткатов можно прокачать:
- рефакторинг — extract to function/method/variable, add missing switch case;
- брейкпойнты — создание Swift Error/Exception/Symbolic/Test Failure;
- Version Control Source — push/pull/fetch/new branch/checkout;
- работа с Swift Package Manager — add/reset/resolve/update.
Как изучать шорткаты в программах? Как минимум, все стандартные приложения macOS имеют вкладку Help с возможностью поиска. Поиск в интерактивном режиме не только проведет вас по всем самым потаённым местам, но и подскажет шорткат (сам поиск удобно вызывать хоткеем ? + ? + /).
Сниппеты
Иногда, работая над проектом, я понимал, что раз за разом пишу одно и то же — так называемый бойлерплейт. Этот процесс тоже можно автоматизировать. К счастью, сейчас есть много очень хороших решений и они скорей всего вам знакомы: это и Sourcery для генерации кода по шаблону и библиотеки по типу R.Swift для генерации доступа к ресурсам, и другие фреймворки. Но не всегда есть возможность затащить стороннюю зависимость в проект. К тому же есть бойлерплейт-код, где подобные библиотеки не помогут. Зато поможет стандартный инструмент Xcode — сниппеты.
Сниппеты есть для всех ключевых слов языка Swift (и некоторых других) и стандартных конструкций: циклов, ветвлений, функций. Но часто мне нужен не просто
var
, а private/public var
. Точно также мне не нужен просто @testable
, мне нужен @testable import
. Другими словами, я бы хотел оперировать уже готовыми конструкциями, а не собирать их по частям.Изменить стандартные сниппеты нельзя, зато добавить свой совсем просто: выделяем блок кода и в контекстном меню выбираем «Create Code Snippet». Дальше Xcode предложит его настроить: задать имя, добавить описание, платформу, скоуп вызова, и, конечно же, указать комплишн, по которому будет вызываться наш сниппет:

Вот так быстро можно «сгенерировать» код для минимальной работы таблицы (ещё быстрее можно сделать, если сразу в сниппете задать количество строк и возвращать пустую ячейку).
Так выглядит сниппет в библиотеке Xcode (? + ? + L):

Как добавить плейсхолдер: поместите ваш текст внутри конструкции <# MyDescription #>
(лучше добавлять её уже после того, как вы добавили описание, так как она сразу «схлопывается»).
А вот как в два тапа можно сделать импорт целой пачки фреймворков для юнит-тестов:

В проекте «Додо Пиццы» мы пишем тесты с помощью Quick/Nimble. Каждый новый спек начинается с импорта 4–6 фреймворков (минимум), и продолжается телом разного уровня вложенности. Импортировать фреймворки мы уже научились, сделаем это и для тела спеки. Всего пара тапов по клавиатуре и сетап для тестов готов:

Еще один кейс: в нашем проекте для логирования ошибки необходимо описать её в специальном виде: создаем энумку, наследуемся от протокола
Error
, задаем кейсы, устанавливаем код ошибки, описываем различные параметры. Каждый раз по памяти писать неудобно:
Для меня это идеальный кандидат для оптимизации своего времени — пусть сниппет делает все за меня:

А сколько еще таких мест можно улучшить (и всё это бесплатно). Несколько личных примеров кандидатов для сниппета:
- Делегат и data source для таблицы/коллекции (обязательные методы).
- При объявлении методов протокола срабатывал стандартный сниппет функции (с открытыми фигурными скобками). Но мне не нужны скобки в протоколе, поэтому я добавил свой сниппет, без скобок. Теперь не нарадуюсь.

Часто типы данных и функции нужно объявлять с явным типом доступа. Это можно можно завернуть в сниппет.

- weak self для замыканий — guard let weakSelf = self else { return };
- локализация — оборачивание в NSLocalizedString (основное отличие от хоткея описанного выше в том, что здесь мы указываем параметр для бандла).

Шаблоны
Плавно продолжаем тему кодогенерации кода, но теперь поднимемся на уровень выше - шаблоны файлов.
Шаблоны удобны, но Apple не предоставляет инструменты для их разработки и документации. Но можно сделать все ручками, потому что есть доступ к стандартным шаблонам файлов (и проектов) Xcode. Чтобы их найти, перейдём в каталог по этому пути:
// ? + ? + G в Finder
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/File Templates/Source/Cocoa Touch Class
Дальше разместим свои темплейты: создаём папку по пути ниже, её имя будет отображаться в окне Xcode. Я назвал папку Helpers:
~/Library/Developer/Xcode/Templates/Files Templates/Helpers
Шаблон для Xcode — это каталог, куда входят:
- файл шаблона (например,
.swift
или.storyboard
);
.plist
файл с настройками;
- иконки двух размеров для отображения в окне Xcode при создании файла.
Чтобы создать свой шаблон, скопируем папку со стандартным шаблоном Xcode и изменим его под себя. Например, для создания объекта API реквеста у себя в проекте мы используем определенную структуру, где описываем стандартные для запроса вещи: урл, параметры, заголовки.
Часто нам интересны только пара параметров, но всё остальное мы обязаны прописать (обязанность протокола). Как раз для этого случая я создал шаблон файла, который не только экономит мне время, но и сразу подсказывает где и что дописать.
Вот так может выглядеть
.plist
файл в нашем случае:<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "<a href="http://www.apple.com/DTDs/PropertyList-1.0.dtd">http://www.apple.com/DTDs/PropertyList-1.0.dtd</a>">
<plist version="1.0">
<dict>
<key>Platforms</key>
<array>
<string>com.apple.platform.iphoneos</string>
</array>
<key>Kind</key>
<string>Xcode.IDEFoundation.TextSubstitutionFileTemplateKind</string>
<key>Description</key>
<string>Internet request</string>
<key>Summary</key>
<string>Internet request</string>
<key>SortOrder</key>
<string>1</string>
<key>AllowedTypes</key>
<array>
<string>public.swift-source</string>
</array>
<key>DefaultCompletionName</key>
<string>File</string>
<key>MainTemplateFile</key>
<string>___FILEBASENAME___</string>
<key>Options</key>
<array>
<dict>
<key>Default</key>
<string>Some</string>
<key>Description</key>
<string>Name of the request</string>
<key>Identifier</key>
<string>productName</string>
<key>Name</key>
<string>Request name:</string>
<key>NotPersisted</key>
<string>Yes</string>
<key>Required</key>
<string>Yes</string>
<key>Type</key>
<string>text</string>
</dict>
</array>
</dict>
</plist>
Добавил код в
.swift
файл (полный пример на GitHub) и обновил иконки. Теперь можно протестировать создание в Xcode (возможно потребуется его перезапуск). Появилась отдельная секция Helpers с моим шаблоном.
А вот такое окно мы увидим после выбора шаблона:

Вводим имя для реквеста. В итоге будет создан вот такой файл:

Только посмотрите сколько работы за меня делают шаблоны!
Пара моментов:
- У нас есть правило для именования реквестов — постфикс Request в имени. При создании файла мне не нужно об этом заботиться, я только ввожу имя реквеста, и по шаблону будет создан класс с правильным названием и именем файла.
GetMenuRequest
иGetMenuRequest.swift
в данном случае.
- Класс имплементирует протокол, но большинство параметров — дефолтные. После создания файла, шаблон мне «подсказывает» места, которые скорее всего я хочу изменить.
Рассмотрим более интересное применение шаблонов — многофайловые шаблоны с возможностью кастомизации при создании (code variants).
В проекте «Додо Пиццы» мы отделяем вью от котроллера. Если это новый контроллер, то создаем под него сториборд/ксиб. Чтобы создать один экран, нужно создать минимум 3 файла: вью, контроллер и сториборд. Помимо этого, контроллер должен быть связан с вью, а сториборд иметь ссылки на вью и контроллер. При этом, мне не всегда нужно создавать файл сториборда (если он уже есть), или файл с вью (если она не нужна). В этой ситуации помогут многофайловые шаблоны с кастомизацией.
В нашем случае нужно будет создать 4 папки для шаблона:
- просто контроллер;
- контроллер и сториборд;
- контроллер и вью;
- контроллер, вью и сториборд;
Вот так будет выглядеть иерархия:
- ViewController.xctemplate
- — UIViewController
- — UIViewControllerStoryboard
- — UIViewControllerView
- — UIViewControllerViewStoryboard
- — TemplateIcon.png
- — TemplateIcon@2x.png
- — TemplateInfo.plist
Здесь уже привычные файлы с иконкой и конфигурацией, но сами шаблоны хранятся в папках. В зависимости от того, какие параметры мы укажем в Xcode при создании контроллера, выберется нужна папка.
Вот так может выглядеть plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "<a href="http://www.apple.com/DTDs/PropertyList-1.0.dtd">http://www.apple.com/DTDs/PropertyList-1.0.dtd</a>">
<plist version="1.0">
<dict>
<key>Kind</key>
<string>Xcode.IDEFoundation.TextSubstitutionFileTemplateKind</string>
<key>Description</key>
<string>ViewController class</string>
<key>Summary</key>
<string>ViewController class</string>
<key>SortOrder</key>
<string>1</string>
<key>DefaultCompletionName</key>
<string>ViewController</string>
<key>Platforms</key>
<array>
<string>com.apple.platform.iphoneos</string>
</array>
<key>Options</key>
<array>
<dict>
<key>Identifier</key>
<string>viewControllerName</string>
<key>Required</key>
<true/>
<key>Name</key>
<string>ViewController:</string>
<key>Description</key>
<string>The name of the view controller class to create</string>
<key>Type</key>
<string>text</string>
<key>NotPersisted</key>
<true/>
</dict>
<dict>
<key>Identifier</key>
<string>cocoaTouchSubclass</string>
<key>Required</key>
<string>YES</string>
<key>Name</key>
<string>Subclass of:</string>
<key>Description</key>
<string>What class to subclass in the new file</string>
<key>Type</key>
<string>class</string>
<key>Default</key>
<string>UIViewController</string>
<key>NotPersisted</key>
<true/>
</dict>
<dict>
<key>Identifier</key>
<string>View</string>
<key>Name</key>
<string>Also create View file</string>
<key>Description</key>
<string>Whether to create a View file with the same name</string>
<key>Type</key>
<string>checkbox</string>
<key>Default</key>
<string>true</string>
<key>NotPersisted</key>
<true/>
</dict>
<dict>
<key>Identifier</key>
<string>Storyboard</string>
<key>Name</key>
<string>Also create Storyboard file</string>
<key>Description</key>
<string>Whether to create a Storyboard file with the same name</string>
<key>Type</key>
<string>checkbox</string>
<key>Default</key>
<string>true</string>
<key>NotPersisted</key>
<true/>
</dict>
<dict>
<key>Default</key>
<string>___VARIABLE_viewControllerName___</string>
<key>Identifier</key>
<string>productName</string>
<key>Type</key>
<string>static</string>
</dict>
</array>
</dict>
</plist>
А вот что получим в итоге:

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

Сила шаблонов в том, что на уровне создания файла можно конфигурировать, что именно нужно создать. Например, можно создать шаблон для VIPER-модуля и при создании указывать только то, что вам нужно (презентер с интерактором или весь модуль целиком).
Бонус секция для шаблонов
Как раньше упоминал, для шаблонов нет официальной документации и инструментов для их создания. Возможности шаблонов «перебираются» энтузиастами на основе стандартных шаблонов Xcode. Но есть одна фича, описание которой я не видел ни в одной статье по шаблонам (возможно, эта будет первой).
Фича в том, что в шаблоне мы можем сконфигурировать текстовое поле так, что оно будет выступать в роли превью для вводимого текста. Например, это можно видеть при создании нового проекта — поле
Bundle Identifier
меняется в зависимости от поля Product Name
. В моем примере это выглядит так:
Потрясающе, ведь теперь я знаю, что мне не нужно дописывать бойлерплейт части
ViewController
и View
.Сделать это просто: в
.plist
добавим новое текстовое поле, где в default-параметре укажем переменную для интересующего идентификатора.// Поле ввода имени ViewController
<dict>
<key>Default</key>
<string>Massive</string>
<key>Identifier</key>
<string>productName</string>
<key>Required</key>
<true/>
<key>Name</key>
<string>ViewController:</string>
<key>Description</key>
<string>The name of the view controller class to create</string>
<key>Type</key>
<string>text</string>
<key>NotPersisted</key>
<string>YES</string>
</dict>
// Превью имени ViewController
<dict>
<key>NotPersisted</key>
<string>Yes</string>
<key>Default</key><string>___VARIABLE_productName:identifier___ViewController</string>
<key>Description</key>
<string>ViewController</string>
<key>Identifier</key>
<string>previewViewController</string>
<key>Name</key>
<string>ViewController:</string>
<key>Type</key>
<string>static</string>
</dict>
Выглядит эффектно. Спасибо @ihppie за то, что рассказал про эту фичу.
Итог
С помощью простых и стандартных вещей можно избежать рутины и значительно сэкономить не только свое время, но и время команды. Все рассмотренные приемы позволяют фокусироваться на коде, а не взаимодействии с IDE во время его написания.
- Тренируйте шорткаты — работа на тачпаде/мышкой будет замедлять вас. Многие операции мышкой и так требуют зажатия клавиш, почему бы полностью не перебраться на клавиатуру?
- Используйте сниппеты для часто повторяемых, неделимых конструкций, project-specific кейсов.
- Создавайте шаблоны и управляйте не только создаваемым файлом, но и сопутствующими (code variants).
Код со всеми примерами в репозитории на GitHub.
Делитесь в комментариях своими джедайскими техниками работы с кодом, что используете и в каких количествах, как учили или учите — вместе мы станем на один шаг ближе к 10x инженеру. Чтобы не пропустить следующую статью, подписывайтесь на канал Dodo Pizza Mobile и Dodo Engineering.
EuGeniec
Думаю так можно x1.2 достичь.
Для x10 «we have to go deeper», искать рычаг подлиньше. Ну или изначально быть талантливым.
alspirichev Автор
Согласен, но всегда надо с чего-то начинать, поэтому и называется «на пути к».
Fedorkov
10x — это в первую очередь про умение с первого раза выбирать решения (технологии, архитектуру, интерфейсы), которые не придётся потом выкидывать и переделывать.