EasySwift iOS🍏
2.96K subscribers
274 photos
8 videos
438 links
Все самое интересное в мире iOS разработки 🧑🏻‍💻

Предложить статью или новость: @EasySwiftBot

По всем вопросам обращаться к @itereznikov
Download Telegram
Detecting Text Language with NLLanguageRecognizer in Swift

ℹ️ Для определения доминирующего языка текста используется структура LanguageDetector, которая инициализирует NLLanguageRecognizer, обрабатывает строку и возвращает код языка в формате ISO 639-1.

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

⚙️ Можно добавить возможность возвращать оценки уверенности в предсказании языка и использовать языковые подсказки для повышения точности распознавания в многоязычных приложениях.

✔️ NLLanguageRecognizer — это мощный API, который позволяет интегрировать определение языка в приложение без необходимости в серверных вызовах и задержках.

import NaturalLanguage

struct LanguageDetector {
static func languageCode(for text: String) -> String? {
let recognizer = NLLanguageRecognizer()
recognizer.processString(text)
if let language = recognizer.dominantLanguage {
return language.rawValue // "en", "ru", "de", etc.
}
return nil
}
}

static func detectLanguage(for text: String) -> (code: String, confidence: Double)? {
let recognizer = NLLanguageRecognizer()
recognizer.processString(text)
guard let language = recognizer.dominantLanguage else { return nil }
let hypotheses = recognizer.languageHypotheses(withMaximum: 1)
let confidence = hypotheses[language] ?? 0
return (language.rawValue, confidence)
}
Please open Telegram to view this post
VIEW IN TELEGRAM
4
Сам себе Шерлок: 7 способов найти логи и поймать баг на iOS

Очередная база - лонгрид про логи ⚙️

🖥 Статья описывает 7 проверенных способов сбора логов на iOS, включая использование .ips файлов, log collect CLI, Xcode и утилиты Console.

Логи делятся на креш-отчёты, диагностические и аналитические данные, которые помогают выявить причины сбоев и проблем с производительностью приложения.

Для работы с логами могут потребоваться инструменты, такие как Xcode, libimobiledevice и Apple Configurator, а также доступ к устройству по проводу или Wi-Fi.

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

⚠️ Рекомендуется собирать логи сразу после инцидента, так как старые .ips файлы автоматически удаляются системой.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍1
Testing Private Members in Swift with @_private(sourceFile:)

👀 Атрибут @_private(sourceFile:) в Swift позволяет тестировать приватные члены классов, обходя контроль доступа, что полезно для написания более точных юнит-тестов.

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

⚙️ Для использования @_private необходимо включить приватные импорты в модуле с помощью флага -enable-private-imports и использовать условную компиляцию в тестах.

⚠️ Рекомендуется использовать @_private только в тестах, оборачивая его в условные флаги компиляции для обеспечения гибкости и возможности отключения при изменениях в Swift.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥11🔥1
⚡️ Срочно!

На днях команда Swift выпустила…новый инструмент управления многопоточностью Swift SDK для Android 🤔

Странный шаг, честно говоря. KMP вроде бы не стал панацей, с чего вдруг это сработает в обратную сторону…

ℹ️ Но если серьезно, то Swift SDK для Android доступен для загрузки с установщика Windows или отдельно для Linux и macOS.

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

➡️ Более 25% пакетов в Swift Package Index уже совместимы с Android, что упрощает портирование существующих пакетов.

➡️ Рабочая группа по Android разрабатывает документ видения, который определит приоритетные направления для будущей работы с Swift на Android.

Скажите честно, ждали?
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯7👍5❤‍🔥2
Thread-Safe Classes: GCD vs Actors

⚙️ Многопоточность и гонки данных являются распространенными проблемами в программировании, особенно при работе с общими ресурсами, такими как словари.

➡️ Использование конкурентной очереди и синхронных/асинхронных вызовов позволяет создать потокобезопасный кэш, предотвращая гонки данных и обеспечивая целостность состояния.

➡️ Лучшей практикой является использование барьеров для обеспечения эксклюзивного доступа к ресурсам при записи, что позволяет одновременно выполнять чтение.

➡️ Акторы обеспечивают безопасность параллелизма, позволяя только одной задаче одновременно получать доступ к изолированному состоянию, что упрощает синхронизацию.

✔️ Сравнение различных подходов к потокобезопасности показывает, что использование акторов является наиболее современным и безопасным методом для работы с многопоточностью в Swift.

Хорошая статья с кучей примеров, рекомендую к прочтению. 👍
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤‍🔥2
Singletons with Swift Concurrency

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

⚠️ Рекомендуется избегать использование синглтонов и вместо этого использовать паттерн корня компоновки или передавать аргументы в функции.

🔍 Аннотация @MainActor позволяет гарантировать потокобезопасный доступ к синглтону, что упрощает аудит и выявление проблем в коде.

➡️ Среди альтернатив синглтонам рассматриваются кастомные актеры, использование блокировок и аннотация @unchecked Sendable, но каждая из этих опций имеет свои недостатки.

😲 А вы знали, что у Apple есть тоже документация по синглтонам?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Understanding task cancellation and lifetimes in Swift concurrency

ℹ️ В Swift structured concurrency связывает время жизни асинхронной работы с областью, в которой она была создана, автоматически отменяя задачи при завершении этой области.

➡️ Несструктурированные задачи, созданные с помощью Task { ... }, работают независимо и требуют ручной отмены, в то время как Task.detached выполняется полностью независимо от контекста вызова.

➡️ При работе с долгоживущими задачами, такими как AsyncStream, важно управлять временем жизни задачи, чтобы избежать бесконечного выполнения.

⚠️ Отмена задач в Swift не останавливает их немедленно, а устанавливает флаг отмены, который асинхронные операции могут проверять для корректного завершения.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Combine – швейцарский нож iOS-разработчика. Или нет?

ℹ️ Combine — это фреймворк для работы с асинхронными событиями в декларативном стиле, который упрощает управление потоками данных и избавляет от сложностей, связанных с колбэками.

⚙️ Основные компоненты Combine включают Publisher, Subscriber и Subscription, которые взаимодействуют для передачи и обработки данных.

➡️ Combine активно используется в SwiftUI через аннотации @Published и @ObservedObject, что позволяет автоматически обновлять интерфейс при изменении данных.

⚠️ Важно помнить о сохранении подписок, так как их отсутствие может привести к потере данных, а также учитывать, что @Published не сравнивает значения, что может вызвать лишние обновления.

А вы пользуетесь Combine?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8👎2
A deep dive into Collections, Sequences, and Iterators in Swift

⚙️ Sequence в Swift — это базовая единица итерации, которая требует от типа, чтобы он предоставлял новый итератор каждый раз при вызове makeIterator().

🔼 Collection расширяет Sequence, обеспечивая многократную итерацию, стабильный порядок и доступ к индексам, что позволяет оптимизировать производительность.

ℹ️ Цикл for … in фактически преобразуется в вызов makeIterator() и последующий вызов next() для получения элементов, что позволяет избежать ошибок при изменении коллекции во время итерации.

💡 Swift Concurrency вводит AsyncSequence и AsyncIteratorProtocol, позволяя использовать асинхронные итераторы с поддержкой приостановки и обработки ошибок.

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

struct Countdown: Sequence {
let start: Int

func makeIterator() -> Iterator {
Iterator(current: start)
}

struct Iterator: IteratorProtocol {
var current: Int

mutating func next() -> Int? {
guard current >= 0 else { return nil }
defer { current -= 1 }
return current
}
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Using MainActor.assumeIsolated to Solve Legacy API Compatibility Issues with Swift 6

😨 Многие устаревшие API Apple не адаптированы к строгой проверке параллелизма Swift 6, что создает сложности для разработчиков при компиляции кода.

💡 Метод MainActor.assumeIsolated позволяет безопасно создавать UIHostingController в синхронном контексте, что решает проблемы с компиляцией при использовании устаревших API в контексте примера из статьи.

public static func assumeIsolated<T>(_ operation: @MainActor () throws -> T, file: StaticString = #fileID, line: UInt = #line) rethrows -> T where T : Sendable


Несмотря на попытки добавить аннотации @MainActor, компилятор Swift 6 продолжает выдавать ошибки, если код не соответствует требованиям изоляции.

А вы применяли эту функцию, кроме как при отладке? 🤔
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Safer Swift: How ~Copyable Prevents Hidden Bugs

Протокол ~Copyable в Swift 5.9 предотвращает неявное копирование объектов, требуя явного управления владением данными.

⚠️ Копирование структуры, содержащей указатель на файл, может привести к ошибкам, когда оба экземпляра записывают в один и тот же файл.

✔️ Добавление ~Copyable к структуре предотвращает компиляцию кода, если происходит попытка использовать объект после его передачи.

🖥 Краткая справка по модификаторам: borrow (временный доступ для чтения), consume (полное владение) и inout (временный доступ для изменения).

struct FileHandleWrapper: ~Copyable {
let handle: UnsafeMutablePointer<FILE>

init(path: String, mode: String) {
guard let file = fopen(path, mode) else {
fatalError("Failed to open file")
}
self.handle = file
}

func write(_ text: String) {
fputs(text, handle)
}

deinit {
print("Closing file handle")
fclose(handle)
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Prompting users to review your app

🟢 Количество отзывов и их оценки критически важны для успеха вашего приложения в App Store, так как они влияют на алгоритмы рекомендаций и доверие пользователей.

✔️ Используйте RequestReviewAction из StoreKit 2, чтобы запрашивать отзывы у пользователей до трех раз в год, избегая прерывания их работы в приложении.

➡️ Запрашивайте отзывы в конце успешных действий, избегая запроса сразу после запуска приложения или в ответ на действия пользователя.

➡️ Используйте ReviewPromptManager для отслеживания, когда последний раз запрашивался отзыв, чтобы избежать повторных запросов для одной и той же версии приложения.

private func presentReview() {
guard ReviewPromptManager.shared.canRequestReview() else { return }

Task {
try? await Task.sleep(for: .seconds(2))
await requestReview()
ReviewPromptManager.shared.markReviewRequested()
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍62🔥2
MainActorMessage & AsyncMessage: Concurrency-safe notifications

🆕 Apple представила новые протоколы MainActorMessage и AsyncMessage, которые обеспечивают потокобезопасные уведомления, доступные с iOS и macOS 26+.

📣 Старый способ наблюдения за уведомлениями вызывает предупреждения о потокобезопасности, даже если они обрабатываются в главном потоке, из-за неявной изоляции.

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

ℹ️ Протокол AsyncMessage позволяет отправлять уведомления асинхронно из любого контекста изоляции, что улучшает гибкость обработки уведомлений.

struct RecentBuildsChangedMessage: NotificationCenter.AsyncMessage {
typealias Subject = [RecentBuild]

let recentBuilds: Subject
}

extension NotificationCenter.MessageIdentifier where Self == NotificationCenter.BaseMessageIdentifier<RecentBuildsChangedMessage> {

static var recentBuildsChanged: NotificationCenter.BaseMessageIdentifier<RecentBuildsChangedMessage> {
.init()
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32
How to perform a lightweight migration in Core Data

➡️ Легкая миграция в Core Data позволяет автоматически переносить совместимые изменения в модели без потери данных.

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

⚠️ При использовании NSPersistentContainer легкая миграция активируется автоматически. Для ручной настройки используйте параметры NSMigratePersistentStoresAutomaticallyOption и NSInferMappingModelAutomaticallyOption.

ℹ️ Создайте новую версию модели через Xcode, чтобы избежать ошибок несовместимости при изменении существующей модели.

ℹ️Core Data поддерживает изменения, такие как добавление, переименование или удаление сущностей и атрибутов, а также изменение типов отношений.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
GSoC 2025 Showcase: Improved Code completion for Swift

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

🖥 Основная цель проекта - показать полную документацию для элементов автозаполнения и реализовать поддержку запроса помощи по сигнатурам, показывая доступные перегрузки и их документацию.

🔥 Успешно реализовано извлечение полной документации по запросу и значительная часть поддержки помощи по сигнатурам, что улучшает опыт работы в редакторах, таких как VS Code и Neovim.

Признавайтесь, а вы уже пишите под Swift на VS Code или планируете?
Please open Telegram to view this post
VIEW IN TELEGRAM
2
Building Peer-to-Peer Sessions: Sending and Receiving Data with Multipeer Connectivity

Для начала работы с Multipeer Connectivity необходимо создать объект MCPeerID для идентификации устройства и MCSession для установления канала связи между устройствами.

➡️ Данные отправляются с помощью метода send(_:toPeers:with:), где строка сообщения преобразуется в формат Data с кодировкой UTF-8. Обработка ошибок обязательна для успешной передачи.

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

➡️ Метод session(_:didReceive:fromPeer:) используется для обработки полученных данных, которые преобразуются обратно в строку и добавляются в массив полученных сообщений.

Для приглашения другого устройства в сессию используется метод invitePeer(_:using:), который позволяет отправить приглашение на подключение.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Меня снова спросили за Optional

Очередная база 🤩

➡️Опционалы представляют собой перечисление с двумя кейсами: .none и .some(T), что позволяет создавать универсальные контейнеры для различных типов данных.

✔️ Для инициализации опционалов без использования кейсов необходимо подписать их под протоколы ExpressibleByNilLiteral и ExpressibleByIntegerLiteral, что позволяет использовать nil и литералы напрямую.

⚠️ Наиболее популярный способ распаковки опционалов — это оператор nil-coalescing (??), который позволяет подставить значение по умолчанию, если опционал пустой.

ℹ️ Для реализации сравнения опционалов необходимо сначала реализовать протокол Equatable, а затем Comparable, что позволяет использовать операторы равенства и сравнения.

enum MyOptional<T> {
case none
case some(T)
}

extension MyOptional: ExpressibleByIntegerLiteral where T == Int {
init(integerLiteral value: Int) {
self = .some(value)
}
}

extension MyOptional {

static func ?? (optional: MyOptional<T>, defaultValue: @autoclosure () -> T) -> T {
switch optional {
case .none:
return defaultValue()

case let .some(unwrappedValue):
return unwrappedValue
}
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
К какому компоненту отнести тот или иной класс? Мой опыт разделения функциональности между компонентами

🔥 Интересная статья про модулирование архитектуры, зависимостей и организацию проекта в целом.

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

Устойчивость компонента можно оценить с помощью метрики I, которая рассчитывается как Fan-out ÷ (Fan-in + Fan-out), где значение 0 указывает на максимальную устойчивость.

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

✔️ Принципы REP, CCP и CRP помогают определить, как компоненты должны быть связаны, чтобы обеспечить удобство сопровождения и повторного использования, избегая ненужных зависимостей.

На начальных этапах разработки важнее удобство сопровождения, тогда как на более зрелых стадиях акцент смещается на удобство повторного использования компонентов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32
Improving the approachability of data-race safety

🖥 Документ из Swift Evolution описывает видение по повышению удобства Swift 6 concurrency, фокусируясь на устранении ложных ошибок data-race safety в последовательном коде и упрощении миграции. Основные цели — сохранить безопасность памяти, сделать базовый concurrency простым и продвинутое — естественным, с тремя этапами: последовательный код, async без параллелизма, затем parallelism для производительности.

Модель Swift 6 предполагает конкурентность по умолчанию, что приводит к ложным срабатываниям ошибок в коде, который на самом деле является однопоточным.

➡️ Предлагается изменить правила изоляции по умолчанию для модулей, чтобы они были изолированы к главному актеру, что упростит написание однопоточного кода.

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

➡️ Вводится концепция изолированных соответствий, позволяющая типам, изолированным к глобальному актеру, реализовывать протоколы без конфликтов с изоляцией.

ℹ️ Хоть документ и не новый, рекомендую с ним ознакомиться - сможете лучше понимать куда в целом движется развитие языка.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Bridging completion handlers to Swift's async/await

🔍 Если хотели провести миграцию с completion handlers на async/await - загляните в статью. Вот пару советов из нее.

✔️ Функция withCheckedContinuation позволяет создать асинхронную функцию, которая обрабатывает результат из API с обработчиком завершения, обеспечивая безопасное возобновление выполнения.

⚠️ Для API, которые могут возвращать ошибки, можно использовать withCheckedThrowingContinuation, что позволяет обрабатывать ошибки с помощью синтаксиса try await.

🛡 withCheckedContinuation и withCheckedThrowingContinuation обеспечивают проверку на наличие множественных вызовов resume, в то время как withUnsafeContinuation и withUnsafeThrowingContinuation не выполняют таких проверок, что делает их менее безопасными.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥41👍1