Getting to Know TextKit
Многие из вас работают со стандартными дизайн компонентами, такими как UILabel и их почти всегда хватает. Но как только нам нужно сделать что-то более сложное, более производительное или что-то очень кастомное, то на помощь нам приходят более низкоуровневые фреймворки, например, TextKit.
В недавно прошедшей конференции try! Swift Tokyo Conference 2024 как раз был доклаз про TextKit 2, его внутренности и для каких задач его можно использовать.
Многие из вас работают со стандартными дизайн компонентами, такими как UILabel и их почти всегда хватает. Но как только нам нужно сделать что-то более сложное, более производительное или что-то очень кастомное, то на помощь нам приходят более низкоуровневые фреймворки, например, TextKit.
В недавно прошедшей конференции try! Swift Tokyo Conference 2024 как раз был доклаз про TextKit 2, его внутренности и для каких задач его можно использовать.
YouTube
try! Swift Tokyo 2024 - Getting to Know TextKit
After a year of developing an editor component with the TextKit 2 framework, I gained knowledge of best practices and techniques. I am thrilled to share my experience and insights.
Speaker: Marcin Krzyzanowski
try! Swift Tokyo Conference 2024 - try! Swift…
Speaker: Marcin Krzyzanowski
try! Swift Tokyo Conference 2024 - try! Swift…
👍3🔥3🤯1
This media is not supported in your browser
VIEW IN TELEGRAM
New accessibility features
Apple показали новые возможности в сфере «доступности», которые появятся в iOS 18. Что меня прям очень радует:
- отслеживание взгляда пользователя, которое поможет людям с ограниченными возможностями взаимодействовать с контентом
- Music Haptics – новый способ прослушивания музыки для глухих или слабослышащих пользователей
- «Прослушивание нетипичный речи» – улучшение распознавания голоса пользователей с приобретенными или прогрессирующими речевыми заболеваниями
- «Vehicle Motion Cues» – это вообще magic✨ для многих – обещают меньше укачивания при езде в машине и залипании в телефон
Очень круто, что многие эти вещи работаю «on-device» и благодаря вкладу Apple в AI: самое настоящее применение современных технологий для прикладных задач.
Apple показали новые возможности в сфере «доступности», которые появятся в iOS 18. Что меня прям очень радует:
- отслеживание взгляда пользователя, которое поможет людям с ограниченными возможностями взаимодействовать с контентом
- Music Haptics – новый способ прослушивания музыки для глухих или слабослышащих пользователей
- «Прослушивание нетипичный речи» – улучшение распознавания голоса пользователей с приобретенными или прогрессирующими речевыми заболеваниями
- «Vehicle Motion Cues» – это вообще magic
Очень круто, что многие эти вещи работаю «on-device» и благодаря вкладу Apple в AI: самое настоящее применение современных технологий для прикладных задач.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16
Подробно об акторах в Swift
Акторы в Swift 5.5 предназначены для безопасной обработки общего изменяемого состояния и предотвращения гонок данных при работе с многопоточностью.
В Swift акторами гарантируется изоляция данных: все изменяемые свойства и функции в акторе изолированы от прямого доступа извне.
В статье автор приводит примеры работы с акторами, подсвечивает основные моменты при работе с ними, а так же описывает процесс перехода на них.
Акторы в Swift 5.5 предназначены для безопасной обработки общего изменяемого состояния и предотвращения гонок данных при работе с многопоточностью.
В Swift акторами гарантируется изоляция данных: все изменяемые свойства и функции в акторе изолированы от прямого доступа извне.
В статье автор приводит примеры работы с акторами, подсвечивает основные моменты при работе с ними, а так же описывает процесс перехода на них.
Medium
Подробно об акторах в Swift
Не зубрить, но разбираться
👍7🔥3
if and switch expressions
Вдруг вы пропустили, что в Swift 5.9 заехали изменения в использование if и switch: теперь эти операторы можно использовать в качестве выражений. Это позволит писать более понятный код. Например:
можно заменить на:
Кстати, а в котлине это уже давно есть 🥲
Вдруг вы пропустили, что в Swift 5.9 заехали изменения в использование if и switch: теперь эти операторы можно использовать в качестве выражений. Это позволит писать более понятный код. Например:
let bullet: String
if isRoot && (count == 0 || !willExpand) { bullet = "" }
else if count == 0 { bullet = "- " }
else if maxDepth <= 0 { bullet = "▹ " }
else { bullet = "▿ " }
можно заменить на:
let bullet = if isRoot && (count == 0 || !willExpand) { "" }
else if count == 0 { "- " }
else if maxDepth <= 0 { "▹ " }
else { "▿ " }
Кстати, а в котлине это уже давно есть 🥲
GitHub
swift-evolution/proposals/0380-if-switch-expressions.md at main · swiftlang/swift-evolution
This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution
🔥11
Access-level modifiers on import declarations
На текущий момент мы можем добавлять модификаторы доступа только интерфейсам, однако для зависимостей такой функциональности не предусмотрено. При разработке библиотек это может быть проблемой, поскольку можно неявно предоставить доступ к деталям реализации, которые хотелось бы скрыть.
С приходом Swift 6 станет возможным добавлять к импортам зависимостей модификаторы уровня доступа, а именно:
public, package, internal, fileprivate и private.
По умолчанию, в Swift 5 все зависимости публичные, однако в Swift 6 станут с модификатором internal.
Чтобы потестить эти модификаторы на Swift 5.9 нужно добавить флаг:
А чтобы проверить, что будет если все импорты станут internal как в Swift 6, то нужно включить еще один флаг:
Это достаточно серьезные изменения, которые могут сломать обратную совместимость для библиотек. Поэтому советую заранее подготовиться 😉
На текущий момент мы можем добавлять модификаторы доступа только интерфейсам, однако для зависимостей такой функциональности не предусмотрено. При разработке библиотек это может быть проблемой, поскольку можно неявно предоставить доступ к деталям реализации, которые хотелось бы скрыть.
С приходом Swift 6 станет возможным добавлять к импортам зависимостей модификаторы уровня доступа, а именно:
public, package, internal, fileprivate и private.
public import PublicDependency
По умолчанию, в Swift 5 все зависимости публичные, однако в Swift 6 станут с модификатором internal.
Чтобы потестить эти модификаторы на Swift 5.9 нужно добавить флаг:
-enable-experimental-feature AccessLevelOnImport
А чтобы проверить, что будет если все импорты станут internal как в Swift 6, то нужно включить еще один флаг:
-enable-experimental-feature InternalImportsByDefault
Это достаточно серьезные изменения, которые могут сломать обратную совместимость для библиотек. Поэтому советую заранее подготовиться 😉
GitHub
swift-evolution/proposals/0409-access-level-on-imports.md at main · swiftlang/swift-evolution
This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution
👍6❤3🤔2
Вот и прошел основной день долгожданной презентации Apple для разработчиков. На удивление многие прогнозы и слухи сбылись, сама презентация получилась достаточно насыщенной, особенно про AI.
Что меня порадовало:
- отдельный менеджер паролей: давно пора, но искренне жаль сторонние сервисы, им точно станет не легко
- Game Porting Toolkit 2 и игровой режим – опять большой упор в игры, и кажется, Apple хочет повторить свой успех Apple Music и Apple TV, но тягаться с Гейбом будет не просто
- калькулятор на iPad – теперь хотя бы понятно, почему они так долго его не выпускали 😬
- watchOS 11 и Vitals – надеюсь, что это новый виток развития приложения «Здоровье» и задел на сентябрскую презентацию с измерениями большего числа показателей организма
- Apple Intelligence – тут и комментировать не нужно, это
- сотрудничество с OpenAI – это еще более крутая и понятная история, но если будет доступно только в Siri, нативных приложениях и там где есть UITextView, то уже не так радостно и круто
Что было очень не очень и даже обидным:
- visionOS 2 – что вообще поменялось, кроме как 8 стран добавили?
- iOS 18 / iPadOS / tvOS 18 – тут и комментировать нечего: кастомное расположение приложений и возможность их скрывать на рабочем столе, настраиваемый пункт управления и вырвиглазные иконки в темной теме. Просто amazing, который мы все заслужили 🥲
- Tap to Сash: «оплата через AirDrop» – очень крутая фича, но естественно, доступно лишь избранным странам и банкам. Никаких открытых API мы скорее всего не увидим
- Xcode Copilot – я даже засек: уделили ровно 14 секунд нашему главному инструменту. Спасибо, конечно, что рассказали про новый эмоджи генератор, но на главной презентации для разработчиков хотелось бы послушать чуть больше про Xcode.
На самом деле я думаю, что часть из пунктов выше раскроют на предстоящих сессиях и мы увидим еще много нового и интересного.
Stay tuned!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍6💯4👎2❤1🤬1
Swift Testing
Apple представила новый фреймворк для тестирования, который:
- поддерживает Swift Concurrency
- по дефолту запускает тесты параллельно
- заменяет XCTAssertTrue, XCTAssertEqual и другие на достаточно умный макрос #expect()
- позволяет запускать тесты с заранее определенным наборам данных
- более информативно сообщает в случае падения теста
- разработан как open source и он кроссплатформен
Вот пример, как теперь будут выглядеть тесты:
Попробовать можно сейчас с XCode 16 beta. Более подробно можно посмотреть в видео с WWDC.
Apple представила новый фреймворк для тестирования, который:
- поддерживает Swift Concurrency
- по дефолту запускает тесты параллельно
- заменяет XCTAssertTrue, XCTAssertEqual и другие на достаточно умный макрос #expect()
- позволяет запускать тесты с заранее определенным наборам данных
- более информативно сообщает в случае падения теста
- разработан как open source и он кроссплатформен
Вот пример, как теперь будут выглядеть тесты:
@Test("Check video metadata",
.tags(.metadata))
func videoMetadata() {
let video = Video(fileName: "By the Lake.mov")
let expectedMetadata = Metadata(duration: .seconds(90))
#expect(video.metadata == expectedMetadata)
}
Попробовать можно сейчас с XCode 16 beta. Более подробно можно посмотреть в видео с WWDC.
👍16❤1
Run, Break, Inspect: Explore effective debugging in LLDB
Познавательная сессия про отладку и поиск проблем в кодовой базе с помощью LLDB и:
- крашлогов
- обратных вызовов (backtraces)
- брейкпоинтов с действиями и сложными условиями остановки
- "p" команды
Из нового: добавили новый макрос
Познавательная сессия про отладку и поиск проблем в кодовой базе с помощью LLDB и:
- крашлогов
- обратных вызовов (backtraces)
- брейкпоинтов с действиями и сложными условиями остановки
- "p" команды
Из нового: добавили новый макрос
@DebugDescription
, который может заменить протокол CustomDebugStringConvertible
. Пример:
@DebugDescription
struct WatchLaterItem {
let video: Video
let name: String
let addedOn: Date
var debugDescription: String {
"\(name) - \(addedOn)"
}
}
👍7
Demystify explicitly built modules
С ростом кодовой базы растет число зависимостей, которые влияют на время сборки приложения.
В XCode 16 добавили опцию в Build Settings проекта: Explicitly Built Modules, которая позволит быстрее найти проблемное место. В логах сборки приложения будет генерироваться Swift modules report, в котором будут указаны все варианты собранных модулей. Так же эта опция позволит сократить время сборки за счет улучшенного планирования стадий сборки и передачи уже собранных модулей дебагеру.
В видео более подробно про то, что происходит после запуска сборки приложения.
С ростом кодовой базы растет число зависимостей, которые влияют на время сборки приложения.
В XCode 16 добавили опцию в Build Settings проекта: Explicitly Built Modules, которая позволит быстрее найти проблемное место. В логах сборки приложения будет генерироваться Swift modules report, в котором будут указаны все варианты собранных модулей. Так же эта опция позволит сократить время сборки за счет улучшенного планирования стадий сборки и передачи уже собранных модулей дебагеру.
В видео более подробно про то, что происходит после запуска сборки приложения.
👍4
Analyze heap memory
WWDC сессия про анализ часто встречающихся проблем при работе со ссылочными типами и про практики, которые помогают с решением утечек или ростом потребления памяти.
Еще в сессии про:
- устройство кучи
- анализ потребления памяти
- инструменты профилирования
- устройство autoreleasepool
- применимость unowned и weak ссылок
Забавно, что в этой сессия не рассматривается устранение проблем при помощи Swift Concurrency, а все "по старинке" 🤔
WWDC сессия про анализ часто встречающихся проблем при работе со ссылочными типами и про практики, которые помогают с решением утечек или ростом потребления памяти.
Еще в сессии про:
- устройство кучи
- анализ потребления памяти
- инструменты профилирования
- устройство autoreleasepool
- применимость unowned и weak ссылок
Забавно, что в этой сессия не рассматривается устранение проблем при помощи Swift Concurrency, а все "по старинке" 🤔
🔥13
Go small with Embedded Swift
В этой WWDC сессии рассказывается про новую область применения Swift – встраиваемые устройства (Embedded Devices).
Обязательно смотреть, если устали от привычной разработки и хочется чего-нибудь экзотического 😎 Еще интересно тем, что есть достаточно жесткие ограничения по потребляемой памяти и вычислительной мощности. Более того, не все функции языка доступны, поэтому иногда придется искать альтернативные решения.
В этой WWDC сессии рассказывается про новую область применения Swift – встраиваемые устройства (Embedded Devices).
Обязательно смотреть, если устали от привычной разработки и хочется чего-нибудь экзотического 😎 Еще интересно тем, что есть достаточно жесткие ограничения по потребляемой памяти и вычислительной мощности. Более того, не все функции языка доступны, поэтому иногда придется искать альтернативные решения.
🔥6
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