Result builders in Swift
❓ С помощью аннотации
⚙️ Такие конструкторы могут поддерживать условия и циклы, что позволяет создавать более сложные конструкции, такие как условные предложения и массивы строк.
⏩ Swift 5.4 расширяет функциональность конструкторов результатов, позволяя использовать их в пользовательских представлениях SwiftUI, что упрощает создание интерфейсов.
🔗 Работать может не только со строками, но и с разными типами данных.
@resultBuilder
можно создавать функции, которые автоматически объединяют строки без необходимости добавления запятых. @resultBuilder
struct ValidatorBuilder {
static func buildBlock(_ components: Bool...) -> Bool {
components.allSatisfy { $0 }
}
}
func validate(@ValidatorBuilder _ rules: () -> Bool) -> Bool {
rules()
}
let email = "user@example.com"
let isValid = validate {
email.count >= 5
email.contains("@")
!email.hasSuffix(" ")
}
print(isValid)
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10
Yielding and debouncing in Swift Concurrency
ℹ️ Функция
⌛ Дебаунсинг позволяет игнорировать промежуточные данные при вводе пользователем, начиная выполнение задачи только после того, как данные остаются неизменными в течение определенного времени.
🔴 Swift использует модель кооперативного отмены задач, что позволяет отменять предыдущие задачи при вводе новых данных, не останавливая их принудительно.
yield
позволяет приостановить выполнение задачи и вернуть поток в пул для выполнения других асинхронных задач, что помогает избежать блокировки потоков в пуле.struct DataHandler {
func process(json files: [Data]) async throws -> [Item] {
let decoder = JSONDecoder()
var result: [Item] = []
for file in files {
let items = try decoder.decode([Item].self, from: file)
result.append(contentsOf: items)
await Task.yield()
}
return result
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤1
Performing your app actions with Siri through App Shortcuts Provider
Интеграция Siri с действиями приложения позволяет пользователям выполнять команды голосом, что упрощает взаимодействие в ситуациях, когда руки заняты.
⏩ В статье взаимодействие с Siri происходит в
➕ Создание ярлыков для Siri включает добавление фраз, которые позволяют пользователю открывать книги с помощью голосовых команд, улучшая пользовательский опыт.
🟢 Метод
🖥 Добавление альтернативных названий приложения и параметров сущностей позволяет пользователям взаимодействовать с приложением более эффективно и интуитивно.
Интеграция Siri с действиями приложения позволяет пользователям выполнять команды голосом, что упрощает взаимодействие в ситуациях, когда руки заняты.
BooksShelfAskSiri-Starter
- приложение для управления библиотекой книг, включая функции для добавления, просмотра и открытия книг.updateAppShortcutParameters()
обновляет параметры ярлыков каждый раз, когда добавляется или удаляется книга, обеспечивая актуальность команд.import AppIntents
struct BookShelfShortcutsProvider: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: OpenBookIntent(),
phrases: [
"Open a book in \(.applicationName)"
],
shortTitle: "Open a book",
systemImageName: "book"
)
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1
Don't rely on BGAppRefreshTask for your app's business logic
⚙️ Использование BGAppRefreshTask для бизнес-логики приложения не гарантирует выполнение фоновых задач, что может привести к устаревшим данным.
⚠️ Автор столкнулся с проблемами после выпуска приложения, когда фоновая задача не выполнялась, несмотря на успешные тесты в TestFlight.
➡️ Вместо фоновых задач автор теперь обновляет данные при каждом открытии приложения, что не идеально для пользователей виджетов.
✔️ Для надежного обновления данных лучше использовать фоновые уведомления, отправляемые с сервера через APNs, хотя это требует наличия бэкенда.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Strategies to avoid merge conflicts in Xcode Projects
Статья про борьбу с конфликтами в XCode проектах, которые возникают из-за частых изменений в файле
Выделяют несколько вариантов решения:
⏩ Разделение проектов
Организация рабочего пространства в несколько проектов может снизить количество конфликтов, распределяя зависимости, хотя это может немного увеличить время индексации и сборки в Xcode.
⏩ Генерация проектов
Использование инструментов, таких как
⏩ Использование SPM
⏩ Фича XCode 16
В Xcode 16 были введены синхронизированные группы, которые позволяют Xcode автоматически синхронизировать файлы в папке, что упрощает управление проектом и снижает вероятность ошибок.
🖥 Я, в основном, пользовался генерацией. Делитесь своим опытом в голосовании.
Статья про борьбу с конфликтами в XCode проектах, которые возникают из-за частых изменений в файле
project.pbxproj
, который не предназначен для прямого редактирования и обновляется при добавлении, удалении или перемещении файлов.Выделяют несколько вариантов решения:
Организация рабочего пространства в несколько проектов может снизить количество конфликтов, распределяя зависимости, хотя это может немного увеличить время индексации и сборки в Xcode.
Использование инструментов, таких как
Tuist
и XcodeGen
, позволяет определять проекты с помощью языков, таких как Swift или YAML, что снижает вероятность конфликтов за счет использования шаблонов.Swift Package Manager
, изначально инструмент для управления зависимостями, стал популярным менеджером проектов, позволяя использовать шаблоны для снижения конфликтов, но может замедлять работу Xcode.В Xcode 16 были введены синхронизированные группы, которые позволяют Xcode автоматически синхронизировать файлы в папке, что упрощает управление проектом и снижает вероятность ошибок.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Как вы решаете конфликты в XCode проектах?
Anonymous Poll
14%
Разделение проектов
56%
Генерация проекта
16%
SPM
15%
Фича из XCode 16
Making your own custom Optional
❓ В статье описывается, как создать собственный тип
⚠️ Представлен метод
Кстати, статья в разделе Интревью🙂
Optional
в Swift, используя перечисление с двумя случаями: наличие значения и отсутствие (nil)
unwrapped()
, который выбрасывает ошибку, если значение отсутствует, с использованием пользовательского перечисления ошибок CustomOptionalError
.Кстати, статья в разделе Интревью
enum CustomOptional<T> {
case some(T)
case none
var value: T? {
switch self {
case .some(let value):
return value
case .none:
return nil
}
}
func unwrapped() throws -> T {
switch self {
case .some(let value):
return value
case .none:
throw CustomOptionalError.valueIsNil
}
}
// MARK: - Custom Optional Error enum
enum CustomOptionalError: Error {
case valueIsNil
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤1
Factory for DI
Отличная статья про реализацию DI.
Автор проводит сравнение трех подходов:
- паттерн фабрика
-
-
⚙️ Паттерн Фабрики используется для создания объектов, инкапсулируя логику создания в отдельном классе или методе, что способствует поддержанию принципа единственной ответственности. Для крупных проектов использование фабрик может быть недостаточным, так как они не обеспечивают управление жизненным циклом зависимостей и не позволяют легко заменять реализации для тестирования.
ℹ️ Библиотека
🟢 В отличие от
Отличная статья про реализацию DI.
Автор проводит сравнение трех подходов:
- паттерн фабрика
-
Factory
библиотека-
Swinject
Factory
предлагает расширенные возможности для DI, включая управление жизненным циклом, легкость в тестировании и обнаружение циклов зависимостей.Swinject
, библиотека Factory
обеспечивает безопасность на этапе компиляции, что предотвращает ошибки во время выполнения, связанные с незарегистрированными зависимостями.Please open Telegram to view this post
VIEW IN TELEGRAM
👍3👎3😁1
Profiling apps using Instruments
‼️ Apple выпустили хороший курс по работе с инструментами профилирования.
💡 Весь курс направлен на поиск и устранение зависаний, анализ синхронных и асинхронных работ, разгрузку главного потока.
Сам курс рассчитан на 1 час 35 минут.
Если еще не смотрели - то сейчас самое время🔍
Сам курс рассчитан на 1 час 35 минут.
Если еще не смотрели - то сейчас самое время
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍4
Documenting your code with DocC
🖥 DocC — это компилятор документации от Apple, который преобразует текст на основе Markdown в богатую документацию для Swift-фреймворков и пакетов.
➡️ Для добавления документации используйте тройные слэши вместо двойных. Это позволяет компилятору DocC извлекать информацию непосредственно из исходного кода.
➡️ Документация может включать описание параметров, возвращаемых значений и ошибок с использованием ключевых слов 🔗 Для упоминания других типов в документации используйте двойные обратные кавычки, что позволяет DocC создавать ссылки на соответствующие элементы документации.
Parameters
, Returns
и Throws.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Rules of Structured Concurrency
⚙️ Структурированные задачи (например,
⚠️ Существуют три основных правила:
- правило завершения группы
- правило отмены группы
- правило распространения ошибок, которые применяются только к структурированным задачам.
⏩ Структурированные задачи лучше использовать для выполнения нескольких параллельных операций, в то время как неструктурированные задачи подходят для выполнения работы независимо от текущего контекста.
⏩ Неструктурированные задачи наследуют приоритет и локальные значения задачи, тогда как структурированные задачи не наследуют изолированность акторов, что позволяет им работать параллельно.
async let
и task group
) управляют дочерними задачами, в то время как неструктурированные задачи (например, Task
и Task.detached
) создают независимые деревья задач без родительских связей.- правило завершения группы
- правило отмены группы
- правило распространения ошибок, которые применяются только к структурированным задачам.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥1
NSAttributedString: Formatting Rich Text in Swift
⏩
✔️ Для создания изменяемой строки используется
➡️ Можно изменять цвет текста, шрифт, добавлять зачеркивание и подчеркивание, а также создавать кликабельные ссылки и настраивать стили абзацев для выравнивания и интервалов.
❗️
💡 Рекомендуется кэшировать атрибутированные строки и использовать
NSAttributedString
— это класс, позволяющий добавлять атрибуты, такие как цвет и шрифт, к определенным диапазонам текста, создавая богатый текст с различными стилями в одном строковом объекте.NSMutableAttributedString
, что позволяет добавлять атрибуты к поддиапазонам текста, например, изменять цвет или шрифт отдельных слов.NSAttributedString
можно использовать с UIKit
через свойства attributedText в UILabel
и UITextView
, а также с SwiftUI
, начиная с iOS 15, с помощью нового типа AttributedString
.NSMutableAttributedString
только при необходимости модификации текста для повышения производительности.let attributedString = NSMutableAttributedString(string: "A text with a background color.")
// Applying foreground color to "text"
attributedString.addAttributes(
[.foregroundColor : UIColor.red],
range: NSRange(location: 2, length: 4)
)
// Applying background color to "text with a background"
attributedString.addAttributes(
[.backgroundColor: UIColor.yellow],
range: NSRange(location: 2, length: 22)
)
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🤔1
Rendering quadratic Bézier curves with Metal
💡 Интересная статья про то, как начали использовать упрощенный метода рендеринга квадратичных кривых Безье с помощью Metal. Данный метода основан на алгоритме Kokojima. Он включает в себя создание трафаретного буфера и шейдинга.
⏩ Процесс включает создание треугольного вентиля вокруг начальной точки, рендеринг кривых с использованием контрольных точек и применение шейдера для отсеивания пикселей вне кривой.
⏩ Метод поддерживает как выпуклые, так и вогнутые кривые, что позволяет эффективно обрабатывать самопересекающиеся сегменты.
⏩ Для сглаживания краев используют встроенную многообразную выборку Metal, что упрощает процесс по сравнению с более сложными решениями.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2
iOS Performance tips you probably didn't know (from an ex-Apple engineer)
Крутая статья трюки оптимизации в приложении. Вот краткий обзор.
⚠️
Он может потреблять значительное количество памяти, особенно если он не монохромный. Для уменьшения использования памяти рекомендуется обнулять текст меток в ячейках
➡️ Использование очередей:
Начинайте с последовательных очередей для выполнения задач, а параллельные очереди используйте только в случае необходимости. Это поможет избежать создания лишних потоков и улучшит производительность.
ℹ️ Симуляция предупреждений о памяти:
Некоторые системные компоненты освобождают память только при получении предупреждения о низкой памяти. Вы можете симулировать это в эмуляторе iOS или на тестовом устройстве.
🛡 Избегайте семафоров;
Использование dispatch_semaphore_t для ожидания асинхронной работы может привести к инверсии приоритетов. Вместо этого лучше использовать синхронные прокси с XPC.
✏️ Проблемы с тегами UIView:
Использование тегов в UIView может негативно сказаться на производительности из-за дополнительных затрат на поиск. Лучше избегать их в производительном коде.
Крутая статья трюки оптимизации в приложении. Вот краткий обзор.
UILabel
дорого стоит:Он может потреблять значительное количество памяти, особенно если он не монохромный. Для уменьшения использования памяти рекомендуется обнулять текст меток в ячейках
UITableView/UICollectionView
, когда они скрыты.Начинайте с последовательных очередей для выполнения задач, а параллельные очереди используйте только в случае необходимости. Это поможет избежать создания лишних потоков и улучшит производительность.
Некоторые системные компоненты освобождают память только при получении предупреждения о низкой памяти. Вы можете симулировать это в эмуляторе iOS или на тестовом устройстве.
Использование dispatch_semaphore_t для ожидания асинхронной работы может привести к инверсии приоритетов. Вместо этого лучше использовать синхронные прокси с XPC.
Использование тегов в UIView может негативно сказаться на производительности из-за дополнительных затрат на поиск. Лучше избегать их в производительном коде.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6😱3❤2👍2
How to inspect .ipa files and secure your iOS app from common mistakes
ℹ️ Интересная статья для тех, кто не знал, что можно достать путем анализа .ipa файла приложения.
🤫 Автор выделяет три основных правила для обеспечения базовой безопасности информации.
➡️ Правило 1: Защита данных
Не добавляйте чувствительные данные в
➡️ Правило 2: Избегайте тестовых данных
Не включайте данные для разработки или тестирования в целевые приложения, чтобы избежать утечек информации.
➡️ Правило 3: Защита строковых литералов
Не храните чувствительные ключи и секреты в строковых литералах; используйте методы обфускации или шифрования - через утилиту
🔍 Для более глубокого анализа используйте специальные инструменты, такие как
Не добавляйте чувствительные данные в
Info.plist
, так как этот файл не зашифрован и доступен для чтения.Не включайте данные для разработки или тестирования в целевые приложения, чтобы избежать утечек информации.
Не храните чувствительные ключи и секреты в строковых литералах; используйте методы обфускации или шифрования - через утилиту
strings
можно много чего увидеть.IDA pro
или Hopper
, которые позволяют дизасемблировать приложение и изучить внутренние структуры и не только.Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Swift Reduce: Combining elements into a single value
💡 Метод
⚠️ Метод
➡️ Хотя
reduce
в Swift позволяет объединять элементы коллекции в одно значение, что делает его полезным для преобразования массивов в словари или суммирования чисел.reduce
имеет сложность O(n)
и может использоваться с вариантом reduce(into:)
, который более эффективен, избегая копирования аккумулятора на каждой итерации.reduce
делает код более элегантным, для сложной логики может быть лучше использовать обычные циклы, чтобы повысить читаемость.let animals = ["Dog", "Cat", "Dog", "Bird"]
let counts = animals.reduce(into: [:]) { result, animal in
result[animal, default: 0] += 1
}
// counts == ["Dog": 2, "Cat": 1, "Bird": 1]
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Modern URL construction in Swift
➡️ Swift 5.9 представил макросы, которые позволяют компилировать и валидировать статические URL-строки, улучшая безопасность кода.
➡️ С введением новых API в iOS 16, можно легко создавать динамические URL без опциональных значений, используя методы
✏️ Современные API для создания URL упрощают код, уменьшают вероятность ошибок и позволяют работать с URL более структурированно.
appending.
@freestanding(expression)
public macro staticURL(_ value: StaticString) -> URL = #externalMacro(
module: "StaticURLMacros",
type: "StaticURLMacro"
)
public struct StaticURLMacro: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> ExprSyntax {
// Verify that a string literal was passed, and extract
// the first segment. We can be sure that only one
// segment exists, since we're only accepting static
// strings (which cannot have any dynamic components):
guard let argument = node.arguments.first?.expression,
let literal = argument.as(StringLiteralExprSyntax.self),
case .stringSegment(let segment) = literal.segments.first
else {
throw StaticURLMacroError.notAStringLiteral
}
// Verify that the passed string is indeed a valid URL:
guard URL(string: segment.content.text) != nil else {
throw StaticURLMacroError.invalidURL
}
// Generate the code required to construct a URL value
// for the passed string at runtime:
return "Foundation.URL(string: \(argument))!"
}
}
let url = #staticURL("https://swiftbysundell.com")
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
libdispatch efficiency tips
👀 Нашел тут довольно старую, но актуальную подборку советов по работе с GCD. Вот некоторые из них:
➡️ Создавайте несколько долгоживущих и четко определенных очередей, чтобы использовать их как контексты выполнения в вашем приложении. Обычно достаточно 3-4 очередей.
➡️ Начинайте с серийной обработки и только при обнаружении узких мест переходите к конкурентности, тщательно измеряя производительность.
➡️ Глобальные очереди могут привести к взрыву потоков и неэффективности. Используйте свои собственные очереди для лучшей производительности.
➡️ Некоторые классы и библиотеки лучше проектировать как синхронные API, чтобы избежать проблем с производительностью и сложностью асинхронного кода.
➡️ Проводите реальные тесты производительности вашего продукта, чтобы убедиться, что изменения действительно улучшают скорость, а не ухудшают.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3