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

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

По всем вопросам обращаться к @itereznikov
Download Telegram
Upload iOS App to TestFlight with GitHub Actions and Fastlane Match

Если вы проводите деплой приложения руками и вас это достало, то это статья для вас. Автор рассказывает, как провести настройку деплоя используя fastlane, связке с GitHub Secrets для хранения ключей и GitHub actions для построения полноценного workflow.

Неплохая статья для понимания того, как работает Continuous Deployment.
3🔥2
Marking Swift Properties Available by iOS Version

В текущих версиях Swift мы можем пометить структуры, классы и расширения доступными для определенных версий ОС.


@available(iOS 18.0, *)
struct GetQuoteControlWidget: ControlWidget {
// code
}


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


private var _customTool: NSObject? = nil
@available(iOS 18.0, *)
private var customToolWrapper: PKToolPickerCustomItem {
if _customTool == nil {
let tool = PKToolPickerCustomItem(configuration: .init(identifier: someID, name: someName))
_customTool = tool
}
return _customTool as! PKToolPickerCustomItem
}
7
SWIFT BUILD TIMES AND MODULE VERIFICATION

После расширения кодовой базы и рефакторинга, автор разбил приложение на множество модулей и стал замечать просадки в сборке проекта. После исследования он обнаружил, что флаг ENABLE_MODULE_VERIFIER был установлен в YES. Сам флаг отвечает за верификацию модулей на этапе сборки. Автор выключил этот флаг для дебаг сборок и уменьшил время с 3,5 минут до 52 секунд.
Но стоит понимать, что этот флаг не панацея и он лишь экономит время сборки, пропуская один из этапов и перед отправкой релизной сборки его все же стоит включить обратно.
5
Benchmark Package

Не так давно был представлен новый пакет Benchmark. Его основная цель – измерение производительности. Количество метрик из коробки большое: 27.
Так же можно добавлять свои метрики.

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

Выглядит круто и работоспособно.
5
Борьба с утечками памяти: от задачи до победы

Классное видео с мобиуса про борьбу с утечками памяти: тут и про работу с Memory Graph, про который не так много документации и примеры про автоматизацию поиска утечек через UI тесты.
10
Антимат в чате на iOS: как я мешаю пользователям сквернословить

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

Как MVP точно пойдет и не факт, что продуктово имеет смысл делать что-то лучше.
4
Morphology in Swift

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

С iOS 15 Foundation предлагает решение этой проблемы, позволяя автоматически обрабатывать такие ситуации и термины обращения в локализованных строках.


Text("She will receive ^[\(count) games](inflect: true).")


Для более точного управления в Swift можно использовать структуру Morphology, позволяющую выполнять ручное согласование грамматики во время выполнения.
5
Wrapping async-await with a completion handler in Swift

Статья про то, как обернуть async-await кода в completion handler. Вы столкнетесь с таким, например, если используете сторонние библиотеки, которые принимают только хендлеры, а ваша кодовая база на основе Swift Concurrency.


extension Task {
@discardableResult
init<T>(
priority: TaskPriority? = nil,
operation: @escaping () async throws -> T,
queue: DispatchQueue = .main,
completion: @escaping (Result<T, Failure>) -> Void
) where Success == Void, Failure == any Error {
self.init(priority: priority) {
do {
let value = try await operation()
queue.async {
completion(.success(value))
}
} catch {
queue.async {
completion(.failure(error))
}
}
}
}
}
2
The Memory Leak: An Xcode Detective Story

История о том, как инженер пытался отладить простой по описанию баг и как глубоко он зашел. Если очень коротко, то проблема была в неправильном использовании [weak self] в кложуре 🫠

Понимание механизмов работы с памятью помогает избегать таких ситуаций.
4🔥21
Announcing Swift 6

Анонсировали релиз Swift 6 🥳 и нас ждет очень много изменений, вот небольшой список:
- поддержка 128-битных целых чисел
- новая библиотека синхронизации, которая включает примитивы, такие как mutex
- новый подход к выбрасыванию ошибок
- владение некопируемых типов
- расширение интеропа с C++
- новый макрос для отображения информации в LLDB @DebugDescription
- фреймворк для тестирования Swift Testing
🔥10
AVAudioSourceNode, AVAudioSinkNode: Low-Level Audio In Swift

AVAudioSourceNode
– узлы AVAudio, предоставляющие способ обработки входных и выходных аудиоданных. Для работы с аудио в режиме реального времени, придется выйти на уровень работы с указателями через UnsafeMutableAudioBufferListPointer и UnsafeMutableBufferPointer. Стоит помнить, что в таком случае управление памятью ложиться на плечи разработчика.

Если вам интересна работа со звуком на низком уровне – эта статья точно для вас.
🔥3
How to keep Date’s microseconds precision in Swift

DateFormatter в Swift теряет точность микросекунд при конвертации даты и времени, что может привести к потенциальным проблемам, например неправильной сортировке данных.

Автор предлагает использовать расширение ISO8601DateFormatter для ручного извлечения микросекунд из строки даты и добавления их к сконвертированному значению Date.


extension ISO8601DateFormatter {
func microsecondsDate(from dateString: String) -> Date? {
guard let millisecondsDate = date(from: dateString) else { return nil }
guard let fractionIndex = dateString.lastIndex(of: ".") else { return millisecondsDate }
guard let tzIndex = dateString.lastIndex(of: "Z") else { return millisecondsDate }
guard let startIndex = dateString.index(fractionIndex, offsetBy: 4, limitedBy: tzIndex) else { return millisecondsDate }
// Pad the missing zeros at the end and cut off nanoseconds
let microsecondsString = dateString[startIndex..<tzIndex].padding(toLength: 3, withPad: "0", startingAt: 0)
guard let microseconds = TimeInterval(microsecondsString) else { return millisecondsDate }
return Date(timeIntervalSince1970: millisecondsDate.timeIntervalSince1970 + microseconds / 1_000_000.0)
}
}
2👍2
Псевдоним типа в Swift

Ключевое слово typealias в Swift позволяет создавать удобный для восприятия код, например:


// Повысить восприятие кода
typealias StringDictionary<T> = Dictionary<String, T>

// Упростить сигнатуры сложных типов и кортежей
typealias CompletionHandler = (Result<String, Error>) -> Void
typealias GridPoint = (x: Int, y: Int)

// Указать ограничения
typealias StringArrayDictionary = Dictionary<String, [String]>



В статье больше примеров с разборами и пояснениями.
🔥11
Как встроить распознавание звуков в ваше iOS приложение на Swift с использованием SoundAnalysis

Если вы хотели попробовать реализовать приложения для распознавания звуков – это статья для вас.
Автор разбирает базовые концепции работы с фреймворком SoundAnalysis. При этом вы можете воспользоваться моделями из коробки, они позволяют распознавать до 300 различных звуков, либо натренировать свою модель через CreateML.
🔥5
Прокачайте свой код с @dynamicMemberLookup

Атрибут dynamicMemberLookup в Swift позволяет обращаться к свойствам объекта, как если бы они были статически определены, что упрощает работу с динамическими структурами данных и делает API более гибким и расширяемым.


json[0]?["name"]?["first"]?.stringValue

// заменится на

json[0]?.name?.first?.stringValue


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

В статье разбираются основные моменты при работе с данным атрибутом на примере.
🔥4
Data alignment: Straighten up and fly right

Хорошо проработанная статья на инженерном языке про работу процессора.

Главная мысль – раскрыть концепцию работы процессора: как он обращается к памяти в 2, 4, 8, 16 или 32-байтовых фрагментах, а не в байтовых кусках, как мы привыкли думать.
3
UNSAFE SWIFT

Уже не новая, но актуальная статья про использование указателей в Swift.
Автор подробно разбирает выравнивание: для чего это может понадобиться, почему порядок типов в объекте имеет значение и как работать с объектами через один из 4 доступных указателей: UnsafeRawPointer, UnsafeMutableRawPointer, UnsafeRawBufferPointer и UnsafeMutableRawBufferPointer


class Foo {
let a: UInt8
let b: UInt16
}
MemoryLayout<Foo>.size // 8
MemoryLayout<Foo>.alignment // 8
MemoryLayout<Foo>.stride // 8


Понимание того, как это работает важно для организации высокопроизводительного кода.
🔥11👀2
Как ускорить запуск iOS-приложения в 2 раза с помощью Network Instrument

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

В статье про использование Network Instrument, который позволяет выявить и решить множество проблем, например, неэффективное использование URLSession, блокирование запросов подключением, долгие редиректы и парсинг больших объемов данных.
🔥5
Как реализовать спойлер-эффект как в Telegram на Swift?

Очень хорошая статья с подробными разборами и комментариями о том, как создать вот такое: спойлер.

Для достижения нужного эффекта автор использует CAEmitterLayer. Однако, помимо лейера тут еще очень много различных тонкостей, которые с первого взгляда не очевидны.
🔥41
Beware UserDefaults: a tale of hard to find bugs, and lost data

Статья про неочевидные проблемы использования UserDefaults: автор столкнулся с необычным поведением, когда UserDefaults стал помечаться как данные, которые требуют шифрования и не доступны до разблокировки устройства. И пользовательские данные просто терялись.

Автор предлагает несколько решений, включая проверку isProtectedDataAvailable и использование собственной реализации UserDefaults для надежного доступа к данным.
🔥3