Вышли новые беты Xcode, macOS Mojave и iOS — и вот основные моменты, которые я усвоил.
Swift 5 для Xcode 10.2 beta
Swift
Прежде всего, последняя бета-версия Xcode идет в комплекте с новой версией Swift:
Apple Swift 5.0 (swiftlang-1001.0.45.7 clang-1001.0.37.7)
Target: x86_64-apple-darwin18.2.0
ABI version: 0.6
Начнем с самых волнующих новостей:
Приложения на Swift больше не включают в себя DLL для стандартной библиотеки Swift и оверлеи Swift SDK в версиях для устройств на iOS 12.2, watchOS 5.2 и tvOS 12.2. В результате Swift-приложения уменьшаются в размере при развертывании для тестирования в TestFlight или при сжатии архива для дистрибутива.
ABI наконец-то станет стабильным, и это отличные новости. На мой взгляд, сегодня это одна из ключевых проблем Swift — не из-за побочных эффектов, а из-за невыполненных обещаний. Некоторые мои знакомые даже переписывают расширения для Apple Watch на Objective-C, чтобы уменьшить размер бинарного файла (примерно с 15 Мб до 1 Мб). Узнать больше о состоянии ABI можно по ссылкам: Информационная панель Swift ABI и Манифест стабильности Swift ABI.
Атрибут @dynamicCallable позволяет вызывать именованные типы так же, как функции, при помощи простого синтаксического сахара. Основное назначение — обеспечение совместимости с динамическими языками. (SE-0216)
Пример:
@dynamicCallable struct ToyCallable {
func dynamicallyCall(withArguments: [Int]) {}
func dynamicallyCall(withKeywordArguments: KeyValuePairs<String, Int>) {}
}
let x = ToyCallable()
x(1, 2, 3)
// Desugars to `x.dynamicallyCall(withArguments: [1, 2, 3])`
x(label: 1, 2)
// Desugars to `x.dynamicallyCall(withKeywordArguments: ["label": 1, "": 2])
Эта тема довольно обширна, и нововведение вызывает у меня смешанные чувства. Пол Хадсон сумел рассказать об этом с нейтральной позиции в статье «Что нового в Swift 5.0».
Режим совместимости со Swift 3 исключен. Поддерживаемые значения флага
-swift-version
— 4, 4.2 и 5.
Уходит эпоха: совместимости на уровне исходного кода со Swift 3 больше нет. Этот шаг был ожидаем, о нём было объявлено в Swift 5 Roadmap, и всё же. Очень советую освежить память, прочитав Swift 5.0 Release Process. Swift 5 уже рядом — будьте готовы.
В режиме Swift 5 switch-операторы над перечислениями, объявленными в Objective-C или приходящими из системных фреймворков, обязаны обрабатывать неизвестные значения — то есть те, которые могут быть добавлены в будущем или которые могут быть определены отдельно в файле реализации Objective-C.
Формально Objective-C позволяет включать в перечисление любое значение, если оно соответствует базовому типу. Эти неизвестные case’ы могут обрабатываться при помощи нового case’a
@unknown default
, который всё так же выдает предупреждение, если любые известные case’ы в switch окажутся упущены. Ими можно управлять и при помощи обычногоdefault
. Если вы задали перечисление в Objective-C и не хотите, чтобы клиентам пришлось обрабатывать неизвестные значения, воспользуйтесь макросомNS_CLOSED_ENUM
вместоNS_ENUM
. Компилятор Swift его распознает и не потребует задаватьdefault
в switch-операторе.В режимах Swift 4 и 4.2 вы также можете пользоваться
@unknown default
. Если этого не сделать и пропустить в switch неизвестное значение, то выполнение программы прервётся — так же, как было в Swift 4.2 и Xcode 10.1 (SE-0192)
Это давняя проблема, по-прежнему доставляющая неудобства, особенно если вы предпочитаете не задавать в switch’ах default
. Помню, сколько мучений мне доставила появившаяся в iOS 12 опция .provisional
в типе UNAuthorizationOptions
. Теперь, с введением case’а unknown
, справляться с такими ситуациями стало куда проще.
Swift Package Manager
Теперь пакеты могут выбирать минимальную требуемую версию для платформы Apple (macOS, iOS) при использовании конфигурационного файла Package.swift из Swift 5. Сборка пакета невозможна, если хотя бы в одной из зависимостей минимальная версия платформы больше чем версия указанная для самого пакета. (SE-0236)
На мой взгляд, это самая главная новость, касающаяся SPM. По сути, эта фича может решить множество проблем, мешающих SPM стать полезным в iOS-мире. В своей прошлой статье я попробовал проанализировать текущее состояние SPM в контексте iOS-разработки. Кажется, теперь мне придётся пересмотреть сделанные выводы.
Но есть и проблемы:
- в некоторых проектах наблюдается регрессия времени компиляции по сравнению с прошлыми релизами;
- проекты для командной строки вылетают при запуске, выдавая ошибку
dyld: Library not loaded
(библиотека не загружена). Костыль: задайте пользовательскую настройку сборкиSWIFT_FORCE_STATIC_LINK_STDLIB=YES
.
В логе изменений перечислено множество исправленных неполадок и других сведений о Swift 5, которые могут быть важны для вашей сферы деятельности. Просмотрите их: возможно, вы решите использовать наследуемые назначенные инициализаторы с переменным количеством аргументов. Или вдруг вы столкнулись с проблемой взаимной блокировки из-за сложных рекурсивных определений типа с классами и дженериками. Или же псевдонимы дженериков в методе @objc
доставляют вам неудобства.
Xcode 10.2 beta
Компилятор Clang
Появилось множество новых оповещений для компилятора Clang, и большинство из них касается фреймворков и модулей. Этот факт довольно интересен, поскольку он (предположительно) говорит об интеграции Swift Package Manager как инструмента управления зависимостями. Вот, по-моему, самые важные пункты:
- новая диагностика идентифицирует заголовки фреймворка, которые используют включения с кавычками вместо включений в стиле фреймворка. По умолчанию оповещение выключено, но его можно включить, передав
clang
опцию-Wquoted-include-in-framework-header
;- открытые заголовки фреймворка могут ошибочно выполнить
#import
или#include
закрытых заголовков, что приводит к нарушению структуры, а иногда и к циклическому импорту модулей. О таких нарушениях сообщит новая диагностика. Она по умолчанию отключена вclang
и управляется флагом-Wframework-include-private-from-public
;- использование
@import
в заголовках фреймворка не дает использовать их без модулей. Новая диагностика выискивает@import
в заголовках при передаче флага—fmodules
. По умолчанию она отключена и управляется флагом-Watimport-in-framework-header
;- раньше потеря ключевого слова
framework
при объявлении модуля для фреймворка не мешала компиляции, но молча приводила к неправильному результату. Новая диагностика-Wincomplete-framework-module-declaration
и новый фикс предложат вам добавить нужный ключ. Это предупреждение запускается автоматически при передачеclang
флага—fmodules
.
Прежде всего: как их включить? Идите в меню Build Settings для вашего проекта, выберите пункт Apple Clang — Custom Compiler Flags и поставьте нужный флаг в пункте Other C Flags.
Я попробовал собрать старое приложение на Objective-C и обнаружил множество проблем с закрытыми заголовками в открытых заголовках фреймворка:
Также обнаружились проблемы со взятым в кавычки импортом внутри фреймворка:
Советую вам тоже провести подобную диагностику или хотя бы сделать заметку на будущее. Однажды эти проблемы могут доставить немало хлопот.
Система сборки
Есть и приятное обновление в системе сборки кода.
Поиск неявных зависимостей теперь работает и в разделе «другие флаги линкера» по связанным фреймворкам и библиотекам, помеченным
-framework, -weak_framework, -reexport_framework, -lazy_framework, -weak-l, -reexport-l, -lazy-l или —l.
Это новшество также очень интригует. В сущности, оно означает, что теперь вы можете определять неявные зависимости с помощью опции .xcconfi
или даже xcodebuild
, избегая стадий Link / Embed в самом Xcode.
Отладка
Новшества отладчика:
Свойства
UIStackView
теперь показаны в инспекторе визуального отладчика. Визуальный отладчик получил более компактный трёхмерный вид.
Теперь в случае возникновения ошибки из-за нехватки памяти Xcode может автоматически создавать график использования памяти. Вы можете включить создание графиков в окне диагностики в настройках выполнения схемы.
При приближении лимита использования памяти в iOS и watchOS Xcode отображает лимит в отчёте использования памяти.
Видите красную черту? При её достижении Watchdog пришлёт уведомление applicationDidReceiveMemoryWarning
. Я думал, что обновление окажется полезнее, а пока что это просто маленький плюсик.
Отладчик LLDB
Новые плюшки появились и в LLDB:
- Теперь вы можете использовать $0, $1 и другие сокращения при вычислении выражений внутри замыканий.
- Теперь в LLDB имеется новый псевдоним
v
для команды frame variable, служащий для вывода переменных в текущем стеке фрейма. Поскольку при этом не задействуется средство оценки выражений,v
может быть намного быстрее, чемp
илиpo
, а потому предпочтительнее.
Я не обнаружил повышения производительности, однако в некоторых случаях v
обеспечивает лучший вывод — но при этом не является прямой заменой po
и работает только с текущим стеком фрейма с определенными ограничениями. Примеры:
Playgrounds
Мой любимый раздел! Начнём с багов:
Приложение Playgrounds может не запуститься
К несчастью, других новостей о Playgrounds в новой бете не поступало.
Симулятор
Пара слов о симуляторе:
Siri не работает в симуляторах watchOS и iOS.
Синхронизация Pasteboard между macOS и симулированными iOS-устройствами стала надёжнее.
Надеюсь, это действительно так.
Запрос доступа к микрофону на всех симулированных устройствах не будет повторяться.
Это хорошие новости, потому что из-за этой проблемы у многих возникали трудности с CI и агентами сборки. Теперь можно соорудить костыль, или, по крайней мере, дополнить свои руководства по работе с агентами сборки, включив пункт «Запустите симулятор один раз».
Тестирование
xccov
поддерживает объединение нескольких отчётов о покрытии кода (и связанных с ними архивов) в один общий отчёт и архив. Получившийся отчёт может содержать неточности, поскольку между моментами создания отчётов могут произойти изменения в исходных файлах. Если изменений не произошло, отчёт будет верным.- Теперь
xccov
отражает разницу между разными отчётами Xcode о покрытии кода, что можно использовать для вычисления произошедших изменений в покрытии. Например, чтобы подсветить разницу междуbefore.xccovreport
иafter.xccovreport
, вызовите командуxccov
следующим образом:xccov diff --json before.xccovreport after.xccovreport
.- таргеты статических библиотек и фреймворков теперь появляются в отчёте о покрытии в виде записей верхнего уровня — графики показателей покрытия собираются по всем таргетам, включающим статическую библиотеку или фреймворк. При этом также решается проблема, когда исходные файлы статической библиотеки или таргета фреймворка вносятся в отчёт, даже в случае удаления самого таргета из покрытия кода в схеме.
Отличные новости для непрерывной интеграции, особенно демонстрация разницы. Расскажите своим релиз-инженерам или тем, кто занимается подобными вещами.
Впрочем, есть и несколько ограничений, касающихся распараллеливания тестов:
- запись на клонах не работает при включенном распараллеливании;
- профилирование проекта из Xcode ведет себя некорректно с включенным распараллеливанием тестов.
В остальном радует исправление некоторых багов:
Если тестирование провалится из-за падения прогонщика тестов при запуске, Xcode попробует сгенерировать подробное сообщение с описанием ошибки. Эту ошибку можно изучить в логе тестирования, а если вы пользуетесь
xcodebuild
, она появится и вstdout
. Также она содержится в структурированных логах получившегося пакета.
У нас часто возникают подобные неполадки — и мы теряемся в догадках, что произошло. Иногда дело в неправильной компоновке, иногда в перегрузке системы. Теперь же надежность приложения повысится.
В собранных во время тестирования отчётах о вылете больше не теряются важные разделы вроде причины вылета или описания.
Здесь без комментариев, сплошной восторг.
Последняя новость, полезная многим разработчикам: теперь Xcode поддерживает сервис кэширования содержимого macOS. Это означает, что с вы можете создать сервер кэширования в локальной сети, который сэкономит время и деньги при загрузке новых и старых версий Xcode в локальной сети.
Проблемы
В этой бете я столкнулся с несколькими проблемами. В основном они касались инструментов от сторонних разработчиков. Например, carthage
выдает ошибку «Не найдены доступные симуляторы для iOS».
Я проверил доступный симулятор, и, похоже, виноваты неполадки в бете. Кроме того, недоступна загрузка других рантаймов из Xcode — список доступных симуляторов пуст (a radar filled):
$ xcrun simctl list devices --json | grep -A16 12.1
"com.apple.CoreSimulator.SimRuntime.iOS-12-1" : [
{
"availability" : "(unavailable, runtime profile not found)",
"state" : "Shutdown",
"isAvailable" : false,
"name" : "iPhone 5s",
"udid" : "DDD36346-A76F-42E8-80F4-6F11E1EE4BEB",
"availabilityError" : "runtime profile not found"
},
{
"availability" : "(unavailable, runtime profile not found)",
"state" : "Shutdown",
"isAvailable" : false,
"name" : "iPhone 6",
"udid" : "21794717-BC89-45E4-9F57-8CF9D14A87D1",
"availabilityError" : "runtime profile not found"
},
--
Но это ведь просто бета, а список изменений громаден. Запасёмся терпением. Carthage уже изучает ситуацию, все догадки изложены в этом баге.
iOS 12.2 beta
Так-так. Похоже, что в Apple заняты полировкой технического долга и наложением патчей безопасности, так что никаких серьезных новостей, но есть две проблемы:
- есть вероятность, что вы не сможете аутентифицироваться в Wallet после выбора карты;
- есть вероятность, что вы не сможете приобрести предоплаченный тарифный план с помощью мобильной сети.
А еще Apple News теперь доступны в Канаде.
Не переключайтесь.
macOS Mojave 10.14.4 beta
Единственное обновление здесь — возможная проблема с Safari 12.1 после апгрейда с Safari 10.1.2.
После апгрейда до Safari 12.1 с версии Safari 10.1.2 веб-страницы могут отображаться некорректно. (47335741)
Обходной прием: введите в терминале команду defaults delete com.apple.Safari
. Обратите внимание, что при этом вы потеряете все прошлые настройки Safari.
В заключение
Статья вышла куда объёмнее, чем я рассчитывал. Все мои выводы вы найдёте выше. А если вкратце — Swift 5 пришёл!
Спасибо за внимание.
Автор: dive