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

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

По всем вопросам обращаться к @itereznikov
Download Telegram
From 180 cm to 5′ 11″: A Complete Guide to Swift Measurement

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

✏️ API Measurement в Swift позволяет безопасно и удобно работать с единицами измерения, обеспечивая автоматическую конвертацию и форматирование значений.

➡️ Можно выполнять математические операции с объектами Measurement, если они принадлежат одной категории единиц, что упрощает работу с данными.

➡️ Метод formatted() позволяет легко преобразовывать Measurement в удобочитаемый текст с учетом локализации, что делает его полезным для международных приложений.

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

let heightMeasurement = Measurement<UnitLength>(value: 180, unit: .centimeters)

// Division with a scalar
let half = heightMeasurement / 2
print(half.value) // 90.0
print(half) // "90.0 cm"

// Addition: different units can be added; the result is in the category’s base unit
let h180cm = Measurement<UnitLength>(value: 180, unit: .centimeters)
let h1m = Measurement<UnitLength>(value: 1, unit: .meters)
let totalHeight = h180cm + h1m // 2.8 m (base unit of UnitLength is metres)
print(totalHeight) // "2.8 m"

// Comparison with automatic unit handling
h180cm < h1m // false (180 cm ≮ 1 m)

// Ranges respect units too
let range = h1m ... h180cm
range.contains(Measurement(value: 6, unit: .feet)) // false (~1.83 m is outside)
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10
Изоляция с помощью глобальных акторов в Swift Concurrency: варианты на примере @MainActor

🔍 В статье рассматриваются различные подходы к изоляции с использованием @MainActor включают полную изоляцию на уровне типа, изоляцию отдельных методов и свойств, а также частичную изоляцию через расширения.

⚠️ Ошибки, такие как разделение соответствия протоколу и реализации (например, через расширение), могут привести к потере ожидаемой изоляции, несмотря на наличие аннотаций @MainActor.

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

⚙️ Выбор подхода к изоляции зависит от контекста: для взаимодействия с UI лучше использовать полную изоляцию, а для повышения производительности — частичную.

@MainActor
protocol IUpdate {
func update(date: Date) async
}

@Observable
final class LS {
var date: Date = .now
}

// Здесь изоляцию @MainActor получит только update

extension LS: IUpdate {
func update(date: Date) async {
await internalUpdate(date: date)
}
// А здесь изоляция уже не применится

private func internalUpdate(date: Date) async {
self.date = date
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Обсуждем кейсы на митапе Яндекса по мобильной разработке

Я.Субботник — большой митап для мобильных разработчиков. В этот раз кроме докладов участников ждёт практический разрбор кейсов на PeerLab.

PeerLab — камерная встреча с экспертами Яндекса. Для неё мы отобрали актуальные темы из разработки и карьеры. Предложить кейс для обсуждения может каждый участник — приносите их в форму регистрации и приходите на обсуждение!

В Москве точно обсудим:

🔸Kotlin Multiplatform
🔸Карьерное развитие
🔸Платформенные команды
🔸AI в разработке

А в Питере:

T-Shape разработчик
🔸Тестирование
🔸AI в разработке

➡️ Регистрируйтесь и ищите список экспертов-участников дискуссии на сайте
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2👎1
Protecting mutable state with Mutex in Swift

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

➡️ Акторы в Swift удобны для асинхронного кода, но могут усложнить код, тогда как Mutex подходит для быстрого синхронного доступа к данным.

ℹ️ Пример класса Counter показывает, как использовать Mutex для безопасного увеличения и уменьшения счетчика, обеспечивая защиту от гонок данных.

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

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

class Counter {
private let mutex = Mutex(0)

func increment() {
mutex.withLock { count in
count += 1
}
}

func decrement() {
mutex.withLock { count in
count -= 1
}
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
When the Swift Debugger Lies: The Hidden Cost of Compiler Optimizations

👀 Интересный кейс произошел у автора при отладке приложения: перед выходом из функции массив оказался пустой.

func getUserListForAdmin() async -> NetworkResponse<[OtherUser]> {
async let type4Request = RestClient.shared.request(Constants.Network.ENDPOINT_USERS, parameters: ["userType": 4])
async let type2Request = RestClient.shared.request(Constants.Network.ENDPOINT_USERS, parameters: ["userType": 2])

let (result4, result2) = await (type4Request, type2Request)

switch (result4, result2) {
case (.success(let users4), .success(let users2)):
for user in users4 {
user.canSeeThisUsersRequests = users2.contains(where: { $0.id == user.id })
}
return .success(users4) // At this breakpoint, users2 appears EMPTY 🤯
case (.error(let error), _), (_, .error(let error)):
return .error(error)
}
}


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

💡 Чтобы сохранить переменные, такие как users2, используйте withExtendedLifetime(users2) или извлеките их из switch-выражения заранее, чтобы избежать их удаления.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Exploring concurrency changes in Swift 6.2

ℹ️ Swift 6.2 вводит два основных изменения в параллельности: новый флаг по умолчанию nonisolated(nonsending) и выполнение кода на главном акторе по умолчанию с помощью настройки defaultIsolation.

⚠️ Флаг nonisolated(nonsending) позволяет асинхронным функциям наследовать контекст актора вызывающего кода, что уменьшает количество ошибок компиляции и упрощает работу с параллельностью.

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

❗️ Рекомендуется включить оба новых флага для упрощения работы с параллельностью, однако важно избегать избыточного использования @concurrent, чтобы не усложнять код.

actor SomeGenerator {
// not allowed
@concurrent
func randomID() async throws -> UUID {
return UUID()
}

// allowed
@concurrent
nonisolated func randomID() async throws -> UUID {
return UUID()
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2
Swift Enums vs Structs - Picking the Best Tool for the Job

Очередная статья про выбор между Enum и структурами (классы остались за бортом 🫠)

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

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

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

💡 Выбирайте Enums для управления состоянием с фиксированным набором опций и Structs для хранения сложных состояний с несколькими свойствами.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Swift 6 Refactoring in a Camera App - SLIT_STUDIO Development Log

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

⚙️ Разработчик Megabits успешно адаптировал приложение SLIT_STUDIO, используя новые компоненты, такие как actor и GlobalActor, для улучшения структуры кода и безопасности.

⚠️ AVFoundation использует GCD, что не совместимо с Swift Concurrency, требуя от разработчиков находить нестандартные решения для обеспечения потокобезопасности.

➡️ Код приложения был перегружен, и Megabits разделил его на более управляемые компоненты, такие как CaptureManageObject и Recorder, чтобы улучшить читаемость и поддержку.

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

@globalActor actor CameraActor: GlobalActor {
static let shared = CameraActor()
}

@CameraActor class Camera: NSObject {
let captureQueue = DispatchQueue(label: "com.linearCCD.capture")
var captureSession = AVCaptureSession()

var currentDevice: AVCaptureDevice?

var videoInput: AVCaptureDeviceInput?
var audioInput: AVCaptureDeviceInput?
var videoOutput: AVCaptureVideoDataOutput?
var audioOutput: AVCaptureAudioDataOutput?
...
}

@CameraActor class CapturePipeline: NSObject, ObservableObject {
let renderContext: MTIContext
var renderPoolForFilter = RenderPool()
var renderPoolForRecordingImage = RenderPool()
var cameraFeedRenderTask: Task<(), Never>?
...
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Для чего я написал собственный аудиопроигрыватель

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

⚙️ Приложение было создано с использованием SwiftUI для упрощения разработки интерфейса и управления данными, а также SQLite для реализации полнотекстового поиска и хранения данных.

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

🫠 Существующие приложения часто требуют подписки, имеют ограниченные функции и неудобный интерфейс, что побудило автора создать собственное решение.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Unique values in Swift: Removing duplicates from an array

В Swift нет встроенных методов для удаления дубликатов из массива, поэтому необходимо использовать альтернативные подходы, такие как использование Set или создание расширения для массива.

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

➡️ Если порядок важен, можно создать расширение для массива, которое использует протокол Hashable для фильтрации дубликатов, обеспечивая линейную временную сложность.

👀 Выбор между Set и расширением массива зависит от необходимости сохранения порядка элементов: используйте Set, если порядок не важен, и расширение массива, если он важен.

extension Sequence where Iterator.Element: Hashable {
func unique() -> [Iterator.Element] {
var seen: Set<Iterator.Element> = []
return filter { seen.insert($0).inserted }
}
}

print(array.unique()) // prints: [1, 2, 3]
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Как мы превратили iPhone в лабораторный микроскоп с AI и BLE: real-world edge-приложение

⚡️ Крутая статья о применении iPhone в медицине. Тут и задачи компьютерного зрения, и оптимизации кода, и работа с AI.

⚙️ Система превращает обычный лабораторный микроскоп в цифровой сканер с автоматической подачей и съемкой, используя iPhone для управления и анализа клеток крови.

💵 Разработка недорогого комплекта автоматизации микроскопа, стоимость которого составляет ~800 $, что значительно дешевле, чем традиционные автоматические системы, стоящие от 10к $.

💡 Используемые технологии включают AI для распознавания клеток, Bluetooth Low Energy для управления моторизованным столиком и мощные процессоры iPhone для обработки изображений в реальном времени.

🔥 Мобильное приложение обрабатывает видеопоток, детектирует и классифицирует клетки, управляет движением предметного столика и отправляет данные на веб-сервер для анализа.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥101
Using AI and Cursor to localize Xcode String Catalogs


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

➡️ Для экспорта языка из строкового каталога выберите приложение и используйте меню Product > Export Localizations..., чтобы сохранить локализации в отдельные папки .xcloc.

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

➡️ После перевода, импортируйте локализованные файлы обратно в Xcode через Product > Import Localizations..., чтобы обновить строковой каталог с новыми переводами.

А вот промпт, используемый автором:
Translate the selected .xliff file’s body tag to the target-language. For each text, keep the source tag and add a target tag with a state="translated"attribute and the translation as body. Output the result as plain text.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Meet the Foundation Models framework

WWDC прошел и, как обычно, показали много нового и интересного (нет, особенно ужасен новый дизайн Liquid Glass). Для меня самое интересное – это новые AI инструменты и возможности и тут на самом деле было много интересного.

Apple показали фрейморк Foundation Models для работы с llm on-device в приложениях. Из основного:
- полностью нативная реализация и интеграция со swift'ом. Сама модель адаптирована под работу на Apple процессорах
- модель: 3B квантизованная до 2х бит: создать полноценного чат бота с ней не выйдет, но с задачами суммаризации, генерацией / понимаем текста и другими несложными llm-based задачами она более чем может справится
- есть возможность не промптом, а с помощью макросов управлять и структурировать формат ответа модели. Этот подход назвали "guided generation". Если кратко, то мы описываем энамы и структуры, и говорим, что хотим от модели в таком формате получать ответ и будем его именно так и получать
- появится новый инструмент отладки и тестирования работы с моделью
- самое важное и крутое на мой взгляд: "Tool calling": мы можем "зарегистрировать" функции приложения и сказать модели, что она может к ним обращаться и получать из них информации. Это крутое новшество, которое тянет на отдельный пост, который мы позже принесем

Отдельным пунктом хочу еще выделить, что наконец-то Xcode получит интеграцию с chatgpt и другими llm, в том числе и локально запущенными 🔥

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

#wwdc2025
👍10
Code-along: Bring on-device AI to your app using the Foundation Models framework

😮 Продолжаем погружаться в нововведения AI от Apple.

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

Из ключевых моментов:

➡️ Написание хорошего промпта играет ключевую роль в достижении хороших результатов. Для упрощения процесса мы можем воспользоваться макросом #Playground в любом файле и там экспериментировать с получаемыми результатами - ответ будет сразу на канвасе.
Есть две сущности - Prompt и Instructions. Вторая - это что-то вроде системного промпта, недоступного пользователю. Очень полезная штука для предварительной «настройки» модели перед ответом на запросы.
Еще в помощь #Generable и #Guide, но про них нужен отдельный пост 🤫

➡️ Для отладки работы приложения, использующего Foundation Models подвезли новый инструмент. Он так и называется
Foundation Models Instrument

Здесь будет видно и количество времени, потраченное на загрузку ассетов, обозначен трек инференса, отдельно будут вызовы тулов. Выглядит круто. После профилирования можно сразу заняться оптимизацией - например: делать загрузку модели еще до того, как пользователь отправит свой запрос.

#wwdc2025
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6