Explore Swift performance
Swift – лаконичный и интуитивно понятный язык программирования. Однако, за этой простотой мы не всегда явно осознаем, как то или иное решение повлияет на производительность. В том же C при вызове malloc мы всегда видим затраты по памяти.
В сессии проходятся по многим аспектам работы языка на низком уровне.
А еще видео содержит ответы на часто задаваемые вопросы по Swift на собеседованиях 🤫
Swift – лаконичный и интуитивно понятный язык программирования. Однако, за этой простотой мы не всегда явно осознаем, как то или иное решение повлияет на производительность. В том же C при вызове malloc мы всегда видим затраты по памяти.
В сессии проходятся по многим аспектам работы языка на низком уровне.
А еще видео содержит ответы на часто задаваемые вопросы по Swift на собеседованиях 🤫
Apple Developer
Explore Swift performance - WWDC24 - Videos - Apple Developer
Discover how Swift balances abstraction and performance. Learn what elements of performance to consider and how the Swift optimizer...
🔥11
Возможно, кто-то уже замечал подобное, но для некоторых это будет открытием.
Объясняется такое просто: в первом случае мы используем реализацию
которая определена в Foundation. В свою очередь, String из Foundation тянет NString, а значит мы можем использовать все его доступные методы.
А во втором случае мы испльзуем реализацию из стандартной библиотеки.
Поэтому важно следить за тем, какие модули мы импортируем и какие реализации выбираем для использования.
P.S. тут даже баг зарепортили, но, кажется, исправлять это не будут 🫢
Объясняется такое просто: в первом случае мы используем реализацию
public func contains<T>(_ other: T) -> Bool where T : StringProtocol
которая определена в Foundation. В свою очередь, String из Foundation тянет NString, а значит мы можем использовать все его доступные методы.
А во втором случае мы испльзуем реализацию из стандартной библиотеки.
public func contains(_ other: String) -> Bool
Поэтому важно следить за тем, какие модули мы импортируем и какие реализации выбираем для использования.
P.S. тут даже баг зарепортили, но, кажется, исправлять это не будут 🫢
👍18🤯3
Synchronous Mutual Exclusion Lock
Недавно одобрили предложение по внедрению нового примитива синхронизации в Swift - Mutex.
Интересно, что в качестве одной из частей мотивации приводят тот факт, что не все хотят и могут пользоваться акторами. А аналогов без костылей в Swift еще не было.
В статье говорится, что Mutex похож на lock, но проблема в том, что не описано прямо как он реализован.
Ждем в новых версиях Swift 🤔
Недавно одобрили предложение по внедрению нового примитива синхронизации в Swift - Mutex.
class FancyManagerOfSorts {
let cache = Mutex<[String: Resource]>([:])
func save(_ resource: Resource, as key: String) {
cache.withLock {
$0[key] = resource
}
}
}
Интересно, что в качестве одной из частей мотивации приводят тот факт, что не все хотят и могут пользоваться акторами. А аналогов без костылей в Swift еще не было.
В статье говорится, что Mutex похож на lock, но проблема в том, что не описано прямо как он реализован.
Ждем в новых версиях Swift 🤔
GitHub
swift-evolution/proposals/0433-mutex.md at main · swiftlang/swift-evolution
This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution
🔥10
Warning for Retroactive Conformances of External Types
Ретроактивное соответствие в Swift – это возможность добавить соответствие протокола к типу, который не находится под вашим контролем, как правило, путем определения расширения типа в другом модуле. С одной стороны это удобно, с другой:
• может привести к случайному поведению, если два разных модуля добавляют противоречивые соответствия;
• вводит опасности совместимости источников, так как модуль может добавить соответствие, которое нарушает существующий код;
• нарушение «дружелюбной для библиотеки» истории, так как модуль может добавлять соответствия типам, которыми он не владеет.
Для решения этой проблемы предлагают добавить предупреждение в компиляторе.
Его можно будет заглушить использовав новый атрибут @retroactive
Однако в старых версиях Swift его можно будет избежать явно указав источник
Ретроактивное соответствие в Swift – это возможность добавить соответствие протокола к типу, который не находится под вашим контролем, как правило, путем определения расширения типа в другом модуле. С одной стороны это удобно, с другой:
• может привести к случайному поведению, если два разных модуля добавляют противоречивые соответствия;
• вводит опасности совместимости источников, так как модуль может добавить соответствие, которое нарушает существующий код;
• нарушение «дружелюбной для библиотеки» истории, так как модуль может добавлять соответствия типам, которыми он не владеет.
Для решения этой проблемы предлагают добавить предупреждение в компиляторе.
Его можно будет заглушить использовав новый атрибут @retroactive
extension Date: @retroactive Identifiable {
// ...
}
Однако в старых версиях Swift его можно будет избежать явно указав источник
extension Foundation.Date: Swift.Identifiable {
// ...
}
👍4
Typed Throws in Swift: Handling Errors Effectively
Статья про концепцию «выбрасывания ошибок» в Swift, которая позволяет более эффектино обрабатывать ошибки. Ключевые моменты:
- Swift позволяет определять пользовательские типы ошибок, создавая перечисление, соответствующее протоколу Error.
- Throwing функции: Функции, которые могут выбрасывать ошибки, помечаюттся ключевым словом throws.
- Ошибки могут обрабатываться в блоке do-catch.
- Типы, выбрасывающие ошибки, могут так же содержать вложенные ошибки.
Статья про концепцию «выбрасывания ошибок» в Swift, которая позволяет более эффектино обрабатывать ошибки. Ключевые моменты:
- Swift позволяет определять пользовательские типы ошибок, создавая перечисление, соответствующее протоколу Error.
- Throwing функции: Функции, которые могут выбрасывать ошибки, помечаюттся ключевым словом throws.
- Ошибки могут обрабатываться в блоке do-catch.
- Типы, выбрасывающие ошибки, могут так же содержать вложенные ошибки.
static func validate(name: String) throws(ValidationError) {
guard !name. isEmpty else {
throw OtherError.validationFailed
}
}
👍8❤1
Изучаем новые структуры данных для iOS разработчика
Статья про редко используемые структуры данных: Deque, Heap, OrderedSet и OrderedDictionary.
Deque предоставляет возможность работать с коллекцией элементов, к которой можно добавлять и удалять элементы как с начала, так и с конца, с амортизированной сложностью О(1).
Heap (куча) - частично-упорядоченное дерево с эффективными операциями вставки и удаления, обладающее сложностью операций вставки O(log n) и получения минимального/максимального элемента O(1).
OrderedSet и OrderedDictionary это коллекции, в которых поддерживается порядок элементов и обеспечивается уникальность ключей.
Статья про редко используемые структуры данных: Deque, Heap, OrderedSet и OrderedDictionary.
Deque предоставляет возможность работать с коллекцией элементов, к которой можно добавлять и удалять элементы как с начала, так и с конца, с амортизированной сложностью О(1).
Heap (куча) - частично-упорядоченное дерево с эффективными операциями вставки и удаления, обладающее сложностью операций вставки O(log n) и получения минимального/максимального элемента O(1).
OrderedSet и OrderedDictionary это коллекции, в которых поддерживается порядок элементов и обеспечивается уникальность ключей.
Хабр
Изучаем новые структуры данных для iOS разработчика
Мобильные разработчики редко сталкиваются в работе со сложными структурами данных. Как правило, в рутинных задачах вполне достаточно уметь использовать Array , Dictionary и Set . На моей практике даже...
❤9🔥3🥰2🎉1
This media is not supported in your browser
VIEW IN TELEGRAM
Enhancing your app with fluid transitions
iOS 18 будет доступен плавный интерактивный зум-переход. Можно использовать как в SwiftUI, так и в UIKit.
Использовать очень просто: нужно проставить свойство preferredTransition на новом контроллере и передать замыкание, которое вернет вью, с которого мы зумим.
iOS 18 будет доступен плавный интерактивный зум-переход. Можно использовать как в SwiftUI, так и в UIKit.
Использовать очень просто: нужно проставить свойство preferredTransition на новом контроллере и передать замыкание, которое вернет вью, с которого мы зумим.
// Create a detail view controller for the selected item.
let detailViewController = MyDetailViewController(itemID: itemID)
// Set the preferred transition to zoom.
detailViewController.preferredTransition = .zoom { [self] _ in
// Return the thumbnail view for the selected item.
return thumbnail(for: itemID)
}
// Push the detail view controller onto the navigation stack.
navigationController?.pushViewController(detailViewController, animated: true)
👍8🔥4
How to solve problems with bitwise operators in Swift
Бит – это наименьшая часть информации, которая может быть 1 или 0. Swift предлагает операторы для манипуляции битами, такие как OR, AND, LEFT SHIFT и RIGHT SHIFT, которые могут быть использованы для решения задач с битовыми операциями.
Однако, для решения задач, где нужны битовые сдвиги, можно воспользоваться уже готовым типом OptionSet.
P.S. Но я рекомендую много раз подумать, а точно ли вам нужны битовые маски, прежде чем их использовать
Бит – это наименьшая часть информации, которая может быть 1 или 0. Swift предлагает операторы для манипуляции битами, такие как OR, AND, LEFT SHIFT и RIGHT SHIFT, которые могут быть использованы для решения задач с битовыми операциями.
0b00000011 | 0b00000101 // The bitwise OR operator produces 0b00000111
0b00000011 & 0b00000101 // The bitwise AND operator produces 0b00000001
0b00000010 << 1 // The bitwise LEFT SHIFT operator << produces 0b0000100
0b00000010 >> 1 // The bitwise RIGHT SHIFT operator >> produces 0b0000001
Однако, для решения задач, где нужны битовые сдвиги, можно воспользоваться уже готовым типом OptionSet.
struct WeekdayOptions: OptionSet {
let rawValue: Int
static let sun = WeekdayOptions(rawValue: 1 << 0)
static let sat = WeekdayOptions(rawValue: 1 << 1)
static let fri = WeekdayOptions(rawValue: 1 << 2)
static let thu = WeekdayOptions(rawValue: 1 << 3)
static let wed = WeekdayOptions(rawValue: 1 << 4)
static let tue = WeekdayOptions(rawValue: 1 << 5)
static let mon = WeekdayOptions(rawValue: 1 << 6)
}
P.S. Но я рекомендую много раз подумать, а точно ли вам нужны битовые маски, прежде чем их использовать
👍4❤2
A Beginner’s Guide to Code Signing in iOS Development
Must read статья для понимания процесса подписи приложения и публикации.
Code signing – это сложный процесс, включающий создание запроса на сертификат, создание provisioning профиля и подписание кода приложения с использованием инструмента codesign в Xcode. Понимание основополагающих концепций криптографии с открытым ключом, хэш-функций и центров сертификации может помочь вам более эффективно управлять ими, особенно по мере роста вашего проекта.
Must read статья для понимания процесса подписи приложения и публикации.
Code signing – это сложный процесс, включающий создание запроса на сертификат, создание provisioning профиля и подписание кода приложения с использованием инструмента codesign в Xcode. Понимание основополагающих концепций криптографии с открытым ключом, хэш-функций и центров сертификации может помочь вам более эффективно управлять ими, особенно по мере роста вашего проекта.
Medium
A Beginner’s Guide to Code Signing in iOS Development
Certificates, provisioning profiles, code signing, and related concepts are a common part of an iOS engineer’s daily work, and we often…
🔥3✍1
Интересный тред после WWDC
Автор задается вопросом, после просмотра сессии про управление памятью в Swift, есть ли гарантированный способ определения была ли выделена память на куче? Swift не предоставляет способа узнать, скрывает ли тип значения частные ссылочные типы, но можно использовать функцию _isPOD() в стандартной библиотеке для этой цели:
В треде люди делятся другими интересными способами как это определить
Автор задается вопросом, после просмотра сессии про управление памятью в Swift, есть ли гарантированный способ определения была ли выделена память на куче? Swift не предоставляет способа узнать, скрывает ли тип значения частные ссылочные типы, но можно использовать функцию _isPOD() в стандартной библиотеке для этой цели:
There's an _isPOD() (Warning: underscored API!) entry point in the stdlib for this purpose:
print(_isPOD(Int.self)) // true
print(_isPOD(Array<Int>.self)) // false
В треде люди делятся другими интересными способами как это определить
Swift Forums
How to know if a value type includes heap allocations and ref counting
I've been trying to improve my understanding Swift's performance characteristics. John McCall's WWDC talk, Exploring Swift Performance, from this year's WWDC is an excellent resource, and I highly recommend it for anyone who is interested in optimizing their…
🔥5
Async await in Swift: The Full Toolkit
Крутая статья от ребят из Emerge Tools про инструменты Swift Concurrency. Подробно и понятно описаны основные возможности и есть примеры использования таких штук:
➖ async / await и async let
➖ Task и Task group
➖ Actors и MainActor
➖ Sendable
➖ Continuations
➖ AsyncSequence
➖ AsyncStream
➖ Async Algorithms
Статья обязательна к прочтению, особенно если только начинаете использовать Swift Concurrency.
Крутая статья от ребят из Emerge Tools про инструменты Swift Concurrency. Подробно и понятно описаны основные возможности и есть примеры использования таких штук:
Статья обязательна к прочтению, особенно если только начинаете использовать Swift Concurrency.
Please open Telegram to view this post
VIEW IN TELEGRAM
Emergetools
Emerge Tools Blog | Async await in Swift: The Full Toolkit
Understand the range of tools in Swift Concurrency
🔥5
Скрытая (на виду) сила KeyPath'ов
KeyPath'ы в Swift - это параметризованные типами объекты, позволяющие читать и записывать переменные типа Value в значения типа Root. Они представлены в виде классов и образуют иерархию типов, включая AnyKeyPath, PartialKeyPath, KeyPath, WritableKeyPath и ReferenceWritableKeyPath.
KeyPath'ы могут быть конвертированы в функции, объединяться, предоставлять доступ по индексу и использоваться в качестве токенов. Они также поддерживают Type Inference и атрибут @dynamicMemberLookup.
В самой статье автор рассматривает так же примеры использования KeyPath для создания удобных API.
KeyPath'ы в Swift - это параметризованные типами объекты, позволяющие читать и записывать переменные типа Value в значения типа Root. Они представлены в виде классов и образуют иерархию типов, включая AnyKeyPath, PartialKeyPath, KeyPath, WritableKeyPath и ReferenceWritableKeyPath.
KeyPath'ы могут быть конвертированы в функции, объединяться, предоставлять доступ по индексу и использоваться в качестве токенов. Они также поддерживают Type Inference и атрибут @dynamicMemberLookup.
В самой статье автор рассматривает так же примеры использования KeyPath для создания удобных API.
Хабр
Скрытая (на виду) сила KeyPath'ов
Привет. Меня зовут Максим Черноусов, и я занимаюсь iOS-разработкой в Райфе. Я обожаю использовать и дизайнить классные API. А один из самых часто используемых строительных блоков для хороших API в...
🔥3
MIT Professor on Data Abstraction & Object-Oriented Programming
Супер классное видео с автором одного из принципов SOLID. В видео затрагивается немного истории, разбирают технические детали самого принципа и отвечают на разные вопросы.
Советуем смотреть всем, оно небольшое.
Супер классное видео с автором одного из принципов SOLID. В видео затрагивается немного истории, разбирают технические детали самого принципа и отвечают на разные вопросы.
Советуем смотреть всем, оно небольшое.
YouTube
MIT Professor on Data Abstraction & Object-Oriented Programming
Barbara Liskov, MIT EECS Institute Professor: https://www.csail.mit.edu/person/barbara-liskov
Programming Methodology Group: https://pmg.csail.mit.edu
Videographer: Mike Grimmett
Director: Rachel Gordon
PA: Alex Shipps
Programming Methodology Group: https://pmg.csail.mit.edu
Videographer: Mike Grimmett
Director: Rachel Gordon
PA: Alex Shipps
❤🔥3
Non-Sendable types are cool too you know
Sendable - это "маркерный протокол", обозначающий, что тип может свободно передаваться между изолированными доменами. Non-Sendable типы не могут быть переданы между изолированными доменами и остаются в том домене, в котором были созданы.
Non-Sendable типы могут быть полезны для моделирования изменяемого состояния, совместимого с произвольно изолированными клиентами, и могут иметь полезные асинхронные методы. Иными словами, такие типы можно использовать особо не задумываясь о потокобезопасноти.
Использование параметра isolation(any) в сочетании с новыми функциями Swift 6 позволяет non-Sendable типам участвовать в конкурентности, обеспечивая безопасность и гибкость.
Sendable - это "маркерный протокол", обозначающий, что тип может свободно передаваться между изолированными доменами. Non-Sendable типы не могут быть переданы между изолированными доменами и остаются в том домене, в котором были созданы.
Non-Sendable типы могут быть полезны для моделирования изменяемого состояния, совместимого с произвольно изолированными клиентами, и могут иметь полезные асинхронные методы. Иными словами, такие типы можно использовать особо не задумываясь о потокобезопасноти.
Использование параметра isolation(any) в сочетании с новыми функциями Swift 6 позволяет non-Sendable типам участвовать в конкурентности, обеспечивая безопасность и гибкость.
massicotte.org
Non-Sendable types are cool too you know
Sendable gets talked about a lot. And while it is a critical aspect of Swift concurrency, I think non-Sendable types are very interesting and just as important. They are often seen as a problem when facing concurrency issues. But, non-Sendable types can actually…
🔥2
iOS App Launch Optimization: How Cityflo Achieved 2.22x Faster Load Times
Запуск приложения кажется незаметным, пока не становится долгим. И чем больше логики тем сложнее это оптимизировать.
В статье автор поделился опытом ускорения запуска приложения с рассмотрением всех моментов, на которые они сделали упор после анализа времени запуска: оптимизацию библиотек, ленивая инициализация, рефакторинг AppDelegate, удаление избыточной логики и оптимизация последовательности вызовов API.
Запуск приложения кажется незаметным, пока не становится долгим. И чем больше логики тем сложнее это оптимизировать.
В статье автор поделился опытом ускорения запуска приложения с рассмотрением всех моментов, на которые они сделали упор после анализа времени запуска: оптимизацию библиотек, ленивая инициализация, рефакторинг AppDelegate, удаление избыточной логики и оптимизация последовательности вызовов API.
Medium
iOS App Launch Optimization: How Cityflo Achieved 2.22x Faster Load Times
In the fast-paced world of mobile apps, first impressions matter. And what’s the first thing users experience when they open your app? The…
👍3❤2
Streamlining NotificationCenter Usage in Swift
Автор описывает интересный подход использования NotificationCenter у себя в проекте: создание протокола с расширением, содержащим некоторые реализации функций. Это позволяет поддерживать чистоту в коде, а также дает возможность проводить тестирование такой функциональности.
Автор описывает интересный подход использования NotificationCenter у себя в проекте: создание протокола с расширением, содержащим некоторые реализации функций. Это позволяет поддерживать чистоту в коде, а также дает возможность проводить тестирование такой функциональности.
Medium
Streamlining NotificationCenter Usage in Swift
If you’re a Swift developer, NotificationCenter is probably no stranger to you, right? We often use this syntax to trigger functions in our…
❤🔥2
Как вернуть контроль над состоянием данных с RemoteResult
Автор предлагает расширить Result, чтобы сделать его более удобным и преварить его в:
Это позволит лучше управлять состоянием данных и реагирововать на состояние загрузки и «простоя». RemoteResult может быть адаптирован для использования в архитектурах программирования, таких как The Composable Architecture, путем внесения простых изменений для совместимости с логикой сравнения состояний.
Автор предлагает расширить Result, чтобы сделать его более удобным и преварить его в:
enum RemoteResult<Success, Failure: Error> {
case idle
case loading
case success(Success)
case failure(Failure)
}
Это позволит лучше управлять состоянием данных и реагирововать на состояние загрузки и «простоя». RemoteResult может быть адаптирован для использования в архитектурах программирования, таких как The Composable Architecture, путем внесения простых изменений для совместимости с логикой сравнения состояний.
NOP::Nuances of programming
Как вернуть контроль над состоянием данных с RemoteResult
Построим на основе Result универсальный способ обозначать состояния ресурса, чтобы из представлений SwiftUI реагировать на его изменения. Рассмотрим реальное применение этого перечисления и адаптируем его для архитектуры TCA.
❤3👍1😁1
Recursive enums in Swift
Рекурсивные перечисления в Swift позволяют создавать структуры данных, включающие в себя экземпляры самого себя, что полезно для моделирования вложенных или рекурсивных данных.
Рассматривается на примере рекурсивной функции для подсчета общего количества элементов в папке, включая элементы во вложенных папках и через символические ссылки.
Рекурсивные перечисления в Swift позволяют создавать структуры данных, включающие в себя экземпляры самого себя, что полезно для моделирования вложенных или рекурсивных данных.
Рассматривается на примере рекурсивной функции для подсчета общего количества элементов в папке, включая элементы во вложенных папках и через символические ссылки.
enum FileSystemItem {
case file(name: String)
case folder(name: String, items: [FileSystemItem])
indirect case alias(name: String, to: FileSystemItem)
}
Nil Coalescing
Recursive enums in Swift
This post explains how to use recursive enums in Swift, including the indirect keyword, to effectively model and manage complex, hierarchical data structures.
👍5
Subtitle Shenanigans in SwiftUI’s Menu
Компонент Menu из SwiftUI – невероятно сложный API с точки зрения сложности поддерживаемых им взаимодействий. В статье рассматриваются неочевидные способы его настройки и обсуждаются распространенные проблемы, с которыми сталкиваются разработчики при использовании HStack и VStack и предлагаются практические решения для их преодоления.
Статья еще интересна с точки зрения того, как можно разбирать документированные API и находить в них несоответствия, а также искать способы решения.
Компонент Menu из SwiftUI – невероятно сложный API с точки зрения сложности поддерживаемых им взаимодействий. В статье рассматриваются неочевидные способы его настройки и обсуждаются распространенные проблемы, с которыми сталкиваются разработчики при использовании HStack и VStack и предлагаются практические решения для их преодоления.
Статья еще интересна с точки зрения того, как можно разбирать документированные API и находить в них несоответствия, а также искать способы решения.
Jeffverkoeyen
Subtitle Shenanigans in SwiftUI’s Menu — featherless software design
👍3
viewIsAppearing
Некоторые могли пропустить, но на WWDC 2023 было представлено важное дополнение про жизненный цикл контроллера.
Этот метод вызывается после вызова viewWillAppear и перед вызовом viewWillLayoutSubviews. Отлично подходит для fine-tune'а динамического интерфейса или самой презентации контроллера.
Некоторые могли пропустить, но на WWDC 2023 было представлено важное дополнение про жизненный цикл контроллера.
Этот метод вызывается после вызова viewWillAppear и перед вызовом viewWillLayoutSubviews. Отлично подходит для fine-tune'а динамического интерфейса или самой презентации контроллера.
Apple Developer Documentation
viewIsAppearing(_:) | Apple Developer Documentation
Notifies the view controller that the system is adding the view controller’s view to a view hierarchy.
❤🔥9