Хабрахабр

Swift 5.0. Что нового?

Но самой главной целью релиза Swift 5. Swift 5 — долгожданный релиз, включающий в себя несколько десятков улучшений и исправлений. В этой статье вы узнаете, что такое ABI и что стабильный ABI даст iOS/macOS разработчикам. 0 было достижение ABI стабильности. А также проведём разбор нескольких новых фич Swift 5.

ABI можно рассматривать как набор правил, позволяющих компоновщику объединять откомпилированные модули компонента. ABI — бинарный интерфейс приложения.

То, как происходит вызов кода из разных модулей, в том числе системных.
2). Соответственно, в ABI описано следующее.
1). Алгоритмы лэйаута данных в оперативной памяти.
4). Формат передачи аргументов и получение возвращаемого значения из функций.
3). Система типов, дженерики. Управление памятью, ARC.
5).

Бинарная совместимость для iOS/macOS приложений означает, что скомпилированные приложения будут в рантайме совместимы с системными библиотеками, скомпилированными более ранними или более поздними версиями языка. Swift 5 вместе со стабильным ABI предоставляет бинарную совместимость для приложений. 0, будет совместимо с стандартными библиотеками, скомпилированными с Swift 5. Например, приложение, скомпилированное с Swift 5. 0. 1 или Swift 6.

2 и macOS 10. Начиная с iOS 12. 4, операционные системы Apple будут содержать все необходимое для запуска свифтовых приложений. 14. Поэтому приложения, написанные на Swift 5, станут весить примерно на 3-10 мегабайт меньше. Это означает, что приложения, написанные на Swift 5 и более поздних версиях, не будут содержать рантайм и стандартную библиотеку языка.

Если ABI stability позволяет совмещать разные версии свифта в рантайме, то Module stability отвечает за то, как компилируются бинарные фреймворки, написанные на разных версиях языка. Важно отметить, что помимо ABI stability, есть еще Module stability. 1. Module stability появится в Swift 5. И тогда разработчики смогут распространять свои фреймворки не только с открытым исходным кодом, но и в скомпилированном виде.

Плюсы ABI стабильности.

Приложения станут весить меньше.
2). 1). В теории, Apple может писать новые фреймворки полностью на Swift. Ускорение запуска и производительности приложений.
3).

Минусы ABI стабильности.

Например, если в iOS 13 будет встроен Swift 5. Разработчикам придётся учитывать отсутствие в более старых версиях стандартной библиотеки какого-либо нового функционала. 2 разработчики не смогут их использовать. 1 с какими-нибудь новыми классами/функциями в стандартной библиотеке, то при поддержке в приложении iOS 12. (Нужно будет вставлять проверки #available(...) так же, как мы это делаем сейчас для Foundation, UIKit и других платформенных библиотек).

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

Тип Result реализован через enum с двумя кейсами: success и failure:

public enum Result<Success, Failure> where Failure: Error { case success(Success) case failure(Failure) ...
}

Ещё со времен первой версии Swift многие разработчики использовали похожий подход. На самом деле такой подход не нов для Swift-разработчиков. Но теперь, когда в стандартной библиотеке появился свой Result, это упростит взаимодействие с кодом из внешних библиотек.

Пример использования в сервисе загрузок статей:

struct Article { let title: String
} class ArticleService }

Так как Result — это всего лишь enum, то мы можем обработать все его состояния с помощью switch: А вот пример обработки полученного результата.

articleService.fetchArticle(id: 42) { result in switch result { case .success(let article): print("Success: \(article)") case .failure(let error): print("Failure: \(error)") }
}

Чтобы написать литерал такой строки, необходимо к двойным кавычкам по краям добавить символ #. В Swift 5 добавили так называемые raw strings, в которых кавычки и бэкслеш интерпретируются именно как символы, и для их использования в литерале не нужно использовать символ экранирования.

Пример использования кавычек:

// swift 4.2
print("Чтобы вывести строку в \"кавычках\" необходимо добавлять бэкслеш.")
print("Чтобы добавить переход на следующую строку, нужно использовать символы \\n") // swift 5
print(#"В "сырой" строке не нужны бэкслеши перед кавычками"#)
print(#"Чтобы добавить переход на следующую строку, нужно использовать символы \n"#)

Эта фича особенно полезна при написании регулярных выражений:

// swift 4.2
let regex = "^\\(*\\d{3}\\)*( |-)*\\d{3}( |-)*\\d{4}$" // swift 5
let regex = #"^\(*\d{3}\)*( |-)*\d{3}( |-)*\d{4}$"#

Для интерполяции строк после бэкслеша надо добавлять символ #:

// swift 4.2
let string = "Строка с интерполяцией \(variable)" // swift 5
let string = #"Строка с интерполяцией \#(variable)"#

Более подробно можете прочитать в этом предложении.

Начиная с 5-ой версии языка, появилась возможность расширять то, как наши выражения добавляются в конечную строку.
В общем случае достаточно написать расширение к структуре DefaultStringInterpolation и добавить метод с названием appendInterpolation. С помощью интерполяции строк мы можем добавить в строковый литерал значение какой-либо переменной или результат выражения. Например, если мы хотим добавить в строку цену в отформатированном виде:

extension DefaultStringInterpolation { mutating func appendInterpolation(price: Decimal) { let formatter = NumberFormatter() formatter.numberStyle = .currency if let string = formatter.string(from: price as NSDecimalNumber) { appendLiteral(string) } else { appendLiteral(price.description) } } } print("Price of item: \(price: 9.99)")
// Price of item: $9.99

99) в строке с помощью компилятора преобразовалась в вызов метода appendInterpolation(price: Decimal).
Также в методах appendInterpolation мы можем добавить неограниченное число аргументов, как именованных, так и не именованных, с дефолтными значениями или без них. Важно отметить то, что, по сути, конструкция (price: 9.

Более подробно можно прочитать в этом предложении.

Да, мы всё ещё можем использовать оператор взятия остатка от деления %. К числовым типам в стандартной библиотеке добавлен метод проверки кратности isMultiple(of:). Но, кажется, isMultiple(of:) выглядит более наглядно.

let interger = 42
if interger.isMultiple(of: 3) { print("Кратно трем")
} else { print("Не кратно трем")
}

Метод compactMapValues позволяет преобразовать значения словаря, а также отфильтровать их, если само преобразование возвратило nil.

Например, маппинг строковых ключей в тип URL:

let dict = [ "site": "https://www.site.ru/path/to/web/site/page", "other site": "invalid url"
]
let mappedDict: [String: URL] = dict.compactMapValues { URL(string: $0) }
print(mappedDict)
// ["site": https://www.site.ru/path/to/web/site/page]

Вторая пара «ключ/значение» была удалена после маппинга, так как строка не является валидным URL’ом.

2 с помощью конструкции try? В Swift 4. В большинстве случаев это не то, чего ожидает разработчик. можно с лёгкостью получить опциональный тип с несколькими уровнями вложенности. получил поведение, схожее c optional chaining. По этой причине в Swift 5 try? с optional chaining или optional casting результатом выражения будет опционал с одним уровнем вложенности. То есть при комбинации try?

вместе с as?: Пример использования try?

// Swift 4.2
let jsonDict = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
// Тип jsonDict - [String: Any]?? // Swift 5
let jsonDict = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
// Тип jsonDict - [String: Any]?

вместе с методом опционального объекта: Пример использования try?

// Swift 4.2
let article = try? storage?.getArticle()
// Тип article - Article?? // Распаковка
if let first = article, let second = first { first // тип Article? second // тип Article
} // Или так
if case let value?? = article { value // тип Article
} // Swift 5
let article = try? storage?.getArticle()
// Тип article - Article? // Распаковка
if let value = article { value // тип Article
}

Более подробно можно прочитать в этом предложении.

Это означает, что мы сможем вызвать тип как обычный метод.
Если мы помечаем тип как @dynamicCallable, то должны реализовать один (или оба) из методов: Новый атрибут @dynamicCallable позволяет пометить тип как «вызываемый».

func dynamicallyCall(withArguments: <#Arguments#>) -> <#R1#>
func dynamicallyCall(withKeywordArguments: <#KeywordArguments#>) -> <#R2#>

Тип Arguments должен поддерживать протокол ExpressibleByArrayLiteral, тип KeywordArguments должен поддерживать протокол ExpressibleByDictionaryLiteral, а R1 и R2 могут быть любыми типами.

При её вызове можно передать любое количество чисел и получить их сумму: Например, структура Sum.

@dynamicCallable
struct Sum { func dynamicallyCall(withArguments args: [Int]) -> Int { return args.reduce(0, +) }
} let sum = Sum()
let result = sum(1, 2, 3, 4)
print(result) // 10

Аналогично для метода dynamicallyCall(withKeywordArguments:). По сути, компилятор преобразует sum(1, 2, 3, 4) в вызов sum.dynamicallyCall(withArguments: [1, 2, 3, 4]).

Эта фича позволит добавить взаимодействие Swift кода с различными динамическим языками программирования, например, Python или JavaScript.

Более подробно можно прочитать в этом предложении.

Начиная с 5-ой версии Свифта можно использовать оператор «меньше» при проверках версии компилятора в коде:

// Swift 4.2
#if !swift(>=4.2)
// Этот код будет скомпилирован только для свифт 4.2 и меньше
#endif // Swift 5
#if swift(<5)
// Этот код будет скомпилирован только для свифт 4.2 и меньше
#endif

Всего было принято 28 предложений от комьюнити, также включающие в себя повышение производительности строк, улучшения Swift Package Manager и стандартной библиотеки. Это не все возможности и улучшения появившиеся в Swift 5. Полный список изменений и улучшений можно посмотреть в release notes.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть