Подробный обзор всего, что Apple представила в этом году

Внутренний тест: двоичный размер

Чтобы отслеживать прогресс, мы использовали Swift-версию одного из приложений, поставляемых с iOS.

В каждом последующем выпуске мы сокращали разницу. В Swift 5.3 мы уменьшили размер кода в 1,5 раза по сравнению с версией Objective-C.

Однако разные стили приложений приводят к разным двоичным размерам.

Размер двоичного файла MovieSwiftUI

В Swift 5.3 внесены значительные улучшения в размер кода приложений SwiftUI. Мы видим, что размер кода для входа в приложение уменьшился более чем на 40%.

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

Грязная память

Пример схемы памяти

Цель-C

Использование типов значений в Swift имеет некоторые фундаментальные преимущества перед языками, основанными на ссылочных типах.

В Objective-C объектные переменные - это просто указатели. Таким образом, массив содержит указатели на объекты модели. Эти объекты, в свою очередь, содержат указатели на свои свойства. Каждый выделяемый вами объект имеет некоторые накладные расходы, производительность и использование памяти.

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

Swift

Использование типов значений в Swift позволяет избежать необходимости доступа ко многим из этих значений через указатель. Таким образом, UUID могут храниться в объектах Mountain, а небольшая строка Swift может содержать намного больше символов, до 15 кодовых единиц, включая символы, отличные от ASCII.

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

Использование кучи

400 объектов модели

Итак, если мы исследуем тепловую память, используемую массивом из 400 этих объектов модели, мы увидим, что данные модели Swift более компактны.

Накладные расходы на модель и язык / библиотеку

Некоторые программы Swift ранее по-прежнему использовали больше тепловой памяти из-за накладных расходов во время выполнения. Раньше Swift создавал несколько кешей и памяти при запуске. В этих кэшах хранились такие вещи, как конформисты протокола и другие типы информации, а также данные, используемые для соединения типов с Objective-C.

Swift 5.3

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

Чтобы воспользоваться всеми преимуществами этих улучшений, минимальная цель развертывания приложения должна быть установлена ​​на iOS 14.

Уменьшение времени выполнения Swift в стеке пользовательского пространства

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

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

Диагностика

В этом цикле выпуска значительно улучшены ошибки и предупреждения компилятора.

Новая подсистема диагностики в компиляторе Swift

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

Вот пример непонятной диагностики, которую компилятор Swift 5.1 выдал в коде SwiftUI год назад.

Перенесемся в сегодняшний день, и диагностика будет значительно лучше с ошибкой, которая точно скажет вам, в чем проблема.

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

В этом случае применение исправления естественным образом направляет разработчика на предоставление недостающих частей для неполной инициализации TextField.

Завершение кода

Это охватывает все, от вывода о завершении кода, предоставляемого компилятором в SourceKit, до опыта работы с редактором кода Xcode.

Улучшенный вывод проверки типов

Во-первых, значительно улучшился вывод о завершении кандидатов. Здесь компилятор определяет значение тернарного выражения при использовании в неполном словарном литерале.

Автозавершение кода: KeyPath как функция

Автозавершение кода также обеспечивает значения, которые вы ожидаете от некоторых из наиболее динамических функций языка, таких как использование KeyPath в качестве функции.

Скорость завершения кода в 15 раз выше по сравнению с Xcode 11.5

Помимо качества результатов завершения, производительность автозавершения кода значительно улучшилась, в некоторых случаях до 15 раз.

Производительность автозавершения кода в коде SwiftUI

Это особенно полезно для редактирования кода SwiftUI.

Отступы в коде

Отступы кода в Xcode, также работающем на движке SourceKit с открытым исходным кодом, значительно улучшились.

Здесь вы можете увидеть одно из улучшений в коде SwiftUI, взятых из проекта MovieSwiftUI с открытым исходным кодом. Раньше у вас иногда возникали естественные углубления для некоторых связанных доступов.

Но теперь они чисто визуально выровнены. Эти и другие улучшения заметно повлияют на ваш опыт редактирования.

Отладка

Улучшенные сообщения об ошибках при сбоях во время выполнения

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

Повышенная надежность при отладке

Плюсы и минусы использования модулей для отладки

  • LLDB использует модули Clange для определения типов
  • LLDB может столкнуться с ошибками модуля, отличными от ошибок во время компиляции.

Swift импортирует API из Objective-C с помощью модулей Clang. Чтобы разрешить информацию о типах и переменных, LLDB необходимо импортировать все модули Swift и Clang, которые видны в текущем контексте отладки.

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

Использование отладочной информации DWARF для типов Objective-C в Swift

  • LLDB теперь может разрешать типы Objective-C в Swift, используя отладочную информацию.
  • Повышает надежность основных функций отладки, таких как представление переменных Xcode.

В качестве запасного варианта, когда это происходит, LLDB теперь может также импортировать типы C и Objective-C для целей отладки Swift из отладочной информации DWARF. Это значительно увеличивает надежность таких функций, как просмотр переменных Xcode и средство оценки выражений.

Официальная поддержка платформы Swift

  • Платформы Apple
  • Ubuntu 16.04, 18.04, 20.04
  • CentOS 8
  • Amazon Linux 2
  • Windows (скоро!)

Благодаря этим усилиям появляется возможность использовать Swift в большем количестве мест.

Swift на AWS Lambda

Бессерверные функции - это простой способ для разработчиков клиентских приложений разместить свои приложения в облаке.

Теперь это легко сделать в Swift, используя среду выполнения Swift AWS с открытым исходным кодом.

import AWSLambdaRuntime
Lambda.run { (_, evnet: String, callback) in
	callback(.success("Hello, \(event)"))
}

Количество необходимого кода так же просто, как написать «Hello, World!»

Язык и библиотеки

Язык

Синтаксис множественного замыкающего закрытия (SE-0279)

// Multiple trailing closure syntax
UIView.animate(withDuration: 0.3, animations: {
	self.view.alpha = 0
})
⬇️⬇️⬇️
UIView.animate(withDuration: 0.3) {
	self.view.alpha = 0
}

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

Он может быть более кратким и менее вложенным без потери ясности, что значительно упрощает чтение сайта вызова.

Однако ограничение синтаксиса замыкающего замыкания только конечным закрытием ограничивает его применимость.

UIView.animate(withDuration: 0.3, animations: {
	self.view.alpha = 0
}) { _ in
	self.view.removeFromSuperview()
}

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

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

UIView.animate(withDuration: 0.3, animations: {
	self.view.alpha = 0
}, completion: { _ in
	self.view.removeFromSuperview()
})
UIView.animate(withDuration: 0.3) {
	self.view.alpha = 0
}
⬇️
UIView.animate(withDuration: 0.3, animations: {
	self.view.alpha = 0
}) { _ in
	self.view.removeFromSuperview()
}

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

SE-0281

UIView.animate(withDuration: 0.3) {
	self.view.alpha = 0
}
⬇️
UIView.animate(withDuration: 0.3) {
	self.view.alpha = 0
} completion: { _ in
	self.view.removeFromSuperview()
}

Новым в Swift 5.3 является синтаксис множественного замыкающего закрытия. Это расширяет преимущества синтаксиса замыкающего замыкания на вызовы с несколькими аргументами замыкания, и не требуется перенастройки для добавления дополнительного.

Синтаксис множественного замыкающего закрытия также отлично подходит для DSL. Новое Gauge представление SwiftUI используется для указания уровня значения относительно некоторой общей емкости.

Используя преимущества синтаксиса множественного замыкающего закрытия, Gauge может элегантно и постепенно раскрывать точки настройки.

Дизайн API: синтаксис завершающего закрытия

// API design : trailing closure syntax
extension Collection {
	func prefix(while predicate: (Element) -> Bool) -> SubSequence
}
message.body = "Hello WWDC!\n--Kyle"
let summary = message.body.prefix { !$0.isNewline }
assert(summary, "Hello WWDC!"

Лучшим названием для take могло бы быть что-то вроде prefix, которое предполагает, что результат привязан к началу коллекции.

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

Выражения KeyPath как функции (SE-0249)

В Swift 4.1 были введены интеллектуальные KeyPaths: типы, которые представляют неактивированные ссылки на свойства, которые можно использовать для получения и установки их базовых значений.

⬇️

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

⬇️

Вы можете использовать выражение KeyPath как функцию. Это означает, что вы можете передать аргумент KeyPath любому параметру функции с соответствующей подписью, и вы можете удалить любые повторяющиеся объявления, которые вы могли добавить в прошлом, чтобы принять KeyPaths.

@main (SE-0281)

Инструмент для точек входа в программу на основе типов.

Начиная с Swift 1.0, вы можете использовать атрибут UIApplicationMain в делегате приложения, чтобы сообщить компилятору о необходимости создания неявного main.swift, запускающего ваше приложение.

В Swift 5.3 эта функция была обобщена и демократизирована.

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

Это позволит вашим пользователям пометить этот тип с помощью @main, а компилятор сгенерирует неявный main.swift от их имени.

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

Повышенная доступность неявного «я» в закрытии (SE-0269)

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

Но когда вам нужно включить много self точек подряд, это может показаться немного лишним.

В Swift 5.3, если вы включите self в список захвата, вы можете опустить его из тела закрытия.

От вас по-прежнему требуется четко заявить о своем намерении запечатлеть себя. Но теперь цена такой ясности сводится к единственному объявлению.

Однако иногда даже однократное использование self. может казаться ненужным - как в SwiftUI, где self, как правило, является типом значения, что делает ссылочные циклы гораздо менее вероятными.

В Swift 5.3, если self является структурой или перечислением, вы можете полностью опустить его при закрытии.

Оговорки о множественном вылове (SE-0276)

Исторически do операторы catch не были столь выразительны, как switch, что заставляло людей прибегать к переключателям вложенности внутри catch предложений.

В Swift 5.3 грамматика catch предложений была расширена, обеспечивая полную мощность switch падежей. Это позволяет вам сгладить тип сопоставления с образцом из нескольких пунктов прямо в оператор do catch, что значительно упрощает его чтение.

Enum Enhancements

Начиная со Swift 4.1, компилятор смог синтезировать эквивалентное и хешируемое соответствие для самых разных типов.

Однако иногда вы попадаете в ситуации, когда было бы ужасно удобно иметь оператор сравнения.

В Swift 5.3 компилятор научился синтезировать сопоставимое соответствие для квалифицируемых типов перечислений.

Перечислить дела в качестве протокольных свидетелей

В Swift 5.3 случаи перечисления теперь могут использоваться для выполнения требований протокола static var и static func.

Усовершенствования встроенного DSL

Это включало закрытие конструктора для коллективного использования дочерних элементов и основные операторы потока управления, такие как _32 _ / _ 33_.

В Swift 5.3 встроенные DSL были расширены для поддержки операторов сопоставления шаблонов и управления потоком, таких как if let и switch.

У меня есть главное окно для основного пользовательского интерфейса и окно предпочтений для настроек приложения.

Раньше, чтобы использовать синтаксис DSL на верхнем уровне тела, как это, требовалось пометить его с помощью определенного атрибута построителя.

В Swift 5.3 атрибут builder больше не потребуется, потому что мы учим компилятора, как вывести его из требований протокола.

SDK

Поплавок16

Float16 - это стандартный формат с плавающей запятой IEEE 754. Float16 занимает всего два байта памяти, в отличие от числа с плавающей запятой одинарной точности, которое занимает четыре.

Архив Apple

Здесь представлен новый модульный формат архива, основанный на проверенной в боях технологии, которую Apple использует для доставки обновлений ОС.

Идиоматический Swift API

Сюда входит конструктор FileStream, который использует еще одну новую библиотеку, Swift System.

Быстрая система

Необработанные, слабо типизированные интерфейсы, импортированные через наложение Дарвина, могут быть привередливыми и подверженными ошибкам.

Swift System обертывает эти API-интерфейсы, используя такие методы, как строго типизированные структуры, обработка ошибок, аргументы по умолчанию, пространства имен и перегрузка функций, закладывая основу для более идиоматичного системного уровня Swift в SDK.

OSLog

Если вы все еще используете print в качестве решения для ведения журналов, сейчас самое время подумать.

Пакеты

Быстрые цифры

Комплексные числа Swift Numerics совместимы по макету со своими аналогами на языке C, но работают быстрее и точнее.

Swift ArgumentParser

Новый пакет Swift с открытым исходным кодом для синтаксического анализа аргументов командной строки.

Swift StandardLibraryПредварительный просмотр

Теперь вы можете предоставить реализацию предложения StandardLibrary feature в виде отдельного пакета SwiftPM.