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

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

По всем вопросам обращаться к @itereznikov
Download Telegram
Secret Management on iOS

🙅‍♂️ Если по какой-то причине вы храните токены или ключи в исходном коде - у меня для вас плохие новости: так не стоит делать

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

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

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

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

Пусть статья и не новая, но актуальная.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Взлом через картинку в Apple: уроки громкой уязвимости для разработчиков

🚨 Уязвимость PT-2025-34177 (CVE-2025-43300) в системном фреймворке ImageIO позволяет злоумышленникам выполнять произвольный код через вредоносные изображения, что ставит под угрозу миллионы устройств Apple.

‼️ Атака может происходить без взаимодействия пользователя (zero-click), что делает её особенно опасной, так как уязвимость использовалась в реальных атаках на конкретных людей.

🔼 Пользователям рекомендуется обновлять свои устройства до последних версий iOS/Android для уменьшения риска быть атакованным и избегать открытия подозрительных файлов, особенно если они приходят как документы.

Для предотвращения подобных уязвимостей необходимо внедрять процессы безопасной разработки, включая фаззинг и статический анализ кода, а также использовать методы защиты от реверс-инжиниринга.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Debugging Swift Concurrency: “Am I on the Main Actor?”

В Swift 6 важно думать не о потоках, а о акторах, чтобы избежать ошибок с доступом к пользовательскому интерфейсу и тяжелым вычислениям.

⚠️ Используйте MainActor.assertIsolated() для проверки, что код выполняется на главном актере, что помогает выявить ошибки во время разработки.

Можно создавать собственные актеры с помощью @globalActor, что позволяет использовать аналогичные методы проверки изоляции.

➡️ Используйте информацию о очереди в Xcode для понимания контекста выполнения актеров и отладки проблем с многопоточностью.
Please open Telegram to view this post
VIEW IN TELEGRAM
6
Жизненный цикл UIViewController в 2025 году: что изменилось и что устарело

🔍 Методы viewDidUnload и didReceiveMemoryWarning устарели, в то время как новые хуки, такие как viewIsAppearing и viewSafeAreaInsetsDidChange, стали стандартом для работы с UIViewController.

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

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

➡️ Рекомендуется использовать методы updateViewConstraints и traitCollectionDidChange для адаптации интерфейса к изменениям окружения, таким как смена темы или ориентации устройства.

➡️ Методы для восстановления состояния, такие как encodeRestorableState и decodeRestorableState, остаются актуальными, однако большинство разработчиков предпочитают использовать UserDefaults или CoreData для сохранения данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍6
Debug crashes in iOS using MetricKit

⚠️ MetricKit — это система для сбора и анализа отчетов о сбоях на уровне системы, которая была введена в iOS 13, позволяя выявлять сбои, которые традиционные инструменты не могут зафиксировать.

Для начала работы с MetricKit необходимо импортировать его в AppDelegate и подписаться на протокол MXMetricManagerSubscriber, чтобы получать отчеты о сбоях.

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

🔍 Для тестирования реализации MetricKit можно симулировать сбои, такие как выход за пределы массива или принудительное развертывание nil, и проверить, как система реагирует на эти сбои.

class AppDelegate: UIResponder, UIApplicationDelegate, MXMetricManagerSubscriber {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Register as a subscriber to receive metrics and diagnostics
MXMetricManager.shared.add(self)
return true
}

// Implement the required delegate method for diagnostics
func didReceive(_ payloads: [MXDiagnosticPayload]) {
// Process crash reports
for payload in payloads {
if let crashDiagnostics = payload.crashDiagnostics {
handleCrashDiagnostics(crashDiagnostics)
}
}
}

func applicationWillTerminate(_ application: UIApplication) {
// Unsubscribe when the app terminates
MXMetricManager.shared.remove(self)
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
ARC в Swift

🎉 Всех с прошедшим Днем программиста! И чтобы не забывать основы - принес статью про механизм подсчета ссылок.

ARC (Automatic Reference Counting) - это метод управления памятью в Swift, который автоматически отслеживает количество сильных ссылок на объекты и освобождает их, когда счётчик достигает нуля.

⚠️ Циклы сильных ссылок (retain cycles) могут возникать, когда два объекта ссылаются друг на друга, что мешает ARC освободить память. Это может привести к утечкам памяти.

🔗 Weak ссылки не учитываются ARC при подсчёте ссылок, что помогает избежать retain cycles, в то время как unowned ссылки никогда не становятся nil, но могут крашнуть приложение при обращении к уничтоженному объекту.

⚙️ ARC работает на уровне SIL (Swift Intermediate Language), где компилятор автоматически добавляет инструкции подсчёта ссылок, что делает код более чистым и безопасным.

✔️ Автоматический подсчет ссылок упрощает управление памятью, избавляя разработчиков от необходимости вручную управлять ссылками, что делает код более лаконичным и понятным.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥62👍2
Swift 6.2 Released

⚡️ Swift 6.2 выпущена 15 сентября. Кратко, что нового.

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

🔒 В новой версии добавлены типы InlineArray и Span, которые обеспечивают безопасный доступ к памяти и высокую производительность без дополнительных затрат.

🔥 Расширение Swift для VS Code теперь официально подтверждено и включает функции, такие как фоновая индексация и встроенная отладка с LLDB.

Swift 6.2 теперь поддерживает WebAssembly, позволяя создавать приложения для браузеров и других сред выполнения.

⚙️ Библиотеки Swift 6.2 включают новый пакет Subprocess для управления внешними процессами и улучшенный API для NotificationCenter.
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍21🔥1
Не могу не поделиться важной и крутой инфой: мой друг выпустил 10 часовой бесплатный курс!!! про iOS разработку для начинающих 🔥

Если вы начали изучать Swift – обязательно к просмотру. И не забывайте делиться с теми, кто тож хочет начать этот увлекательный путь.

https://www.youtube.com/watch?v=SUKocLwjA5k
🔥8👍52
Как Swift Runtime влияет на производительность iOS-приложений

⚡️ Тут наши ребята рассказывают про производительность - супер объемный и полезный обзор. Вот лишь несколько моментов.

⚙️ Swift Runtime играет ключевую роль в производительности iOS-приложений, особенно в управлении памятью и проверке соответствия типов, что может значительно замедлить работу приложения.

‼️ Метод swift_conformsToProtocolMaybeInstantiateSuperclasses является узким местом производительности, так как он может занимать от 1 до 3 мс на каждом вызове, особенно при использовании операторов as? и as! или методов String(describing:) и String(reflecting:).

⚠️ Рекомендуется избегать использования String(describing:) и операторов as? и as!, а также минимизировать использование type-generic-constraint-ов для повышения производительности приложения.

🤫 Использование type-generic-constraint-ов может значительно замедлить приложение, так как каждый вызов метода swift_conformsToProtocolMaybeInstantiateSuperclasses требует проверки
соответствия для каждого протокола.

💯 Рекомендую к прочтению.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥2
Swift Default Value in String Interpolations

🔥 Swift 6.2 улучшает интерполяцию строк с опциональными значениями, позволяя использовать параметр значения по умолчанию.

При интерполяции строк с опционалами компилятор выдает предупреждение, если не указано значение по умолчанию.

🤫 Теперь можно использовать новый параметр по умолчанию в строке, чтобы она не зависела от типа опционального значения. Однако, он не будет работать с локализацией: LocalizedStringKey не поддерживает такой формат.

// The count is not set
Text("The count is \(count, default: "not set")")
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Строки в Swift

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

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

🖥 Строки могут быть представлены в различных кодировках, таких как unicodeScalars, utf16 и utf8, каждая из которых имеет свои особенности и количество кодовых точек. Сами же строки используют оптимизацию Copy-on-Write, что позволяет эффективно управлять памятью и ускорять доступ к данным.

➡️ Строки Swift могут быть конвертированы в NSString и обратно, что позволяет использовать их в проектах, где смешиваются Swift и Objective-C.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Command tools, threads and QoS

Почему супер навороченные новые мак не могут быстро сжать большую папку через tar? 🤕
Крайне интересная статья, которая поможет лучше разбираться в многопоточности на примере реальной задачи архивирования. Вот краткое содержание.

macOS использует различные уровни QoS для распределения потоков по ядрам процессора, что влияет на производительность. QoS варьируется от 9 (background) до 33 (userInteractive).

ℹ️ Однопоточные процессы, такие как tar, значительно медленнее многопоточных альтернатив, которые могут использовать все доступные производительные ядра.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Feature flags in Swift

🚩 Feature flags в Swift позволяют включать и отключать определенные функциональности. В статье автор приводит в пример в зависимости от конфигурации сборки, таких как Debug, TestFlight и App Store.

По умолчанию в Xcode есть две конфигурации: Debug и Release. Рекомендуется создавать дубликаты для App Store и TestFlight для управления функциональностью.

🔥 Создание перечисления Distribution и структуры FeatureFlags позволяет управлять доступом к функциям в зависимости от текущей конфигурации сборки.

ℹ️ Такой механизм следует рассматривать как временный инструмент и удалять флаги, когда функция готова. Рассмотрите возможность удаленной настройки для мгновенного включения или отключения функций. Крайне полезный инструмент.

public struct FeatureFlags: Sendable, Decodable {
public let requirePaywall: Bool
public let requireOnboarding: Bool
public let featureX: Bool

public init(distribution: Distribution) {
switch distribution {
case .debug:
self.requirePaywall = true
self.requireOnboarding = true
self.featureX = true
case .appstore:
self.requirePaywall = true
self.requireOnboarding = true
self.featureX = false
case .testflight:
self.requirePaywall = false
self.requireOnboarding = true
self.featureX = true
}
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
How to unwrap [weak self] in Swift Concurrency Tasks?

🔍 В Swift, использование [weak self] в замыканиях помогает избежать циклов удержания, но не всегда необходимо, особенно для не-escaping замыканий.

Создание неструктурированного Task может привести к утечкам памяти, если [weak self] используется неправильно, так как Task начинает выполняться сразу после его создания.

Task { [weak self] in
guard let self else { return } // это не решает проблему

let data = await loadData()
let models = await processData(data)
}


✔️ Для предотвращения сильного удержания self в Task, рекомендуется проверять наличие self внутри тела цикла или использовать self? для избежания распаковки.

При выполнении длительных задач, таких как загрузка нескольких страниц, перемещение guard let self внутрь цикла позволяет избежать удержания self дольше, чем это необходимо.

Task { [weak self] in
let data = await loadData()
guard self != nil else { return }

guard let models = await self?.processData(data) else {
return
}

// use models
}
Please open Telegram to view this post
VIEW IN TELEGRAM
4👎2🔥1
Derived Data: 5 Things iOS Developers Do Wrong

😐 Многие разработчики iOS не понимают, для чего предназначена папка Derived Data, что может привести к неэффективному использованию её возможностей.

Удаление всей папки Derived Data может замедлить процесс сборки, так как каждый проект имеет свою собственную папку, и удаление её требует повторной компиляции всех зависимостей.

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

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

🖥 Xcode предоставляет простой способ доступа к папке Derived Data через настройки, что облегчает её использование.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Массивы в Swift

🟢 Принес очередную базу.

ℹ️ Массивы в Swift - это структуры данных, которые хранят коллекции элементов одного типа и поддерживают доступ по индексу за O(1).

Добавление элементов в массив происходит за амортизированное константное время, однако при расширении массива может потребоваться больше времени из-за копирования элементов.

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

👀 Они представляют собой обертку над буфером, который хранит данные в куче. В зависимости от наличия Objective-C runtime, используются разные типы буферов.

Swift реализует механизм Copy-on-Write, который позволяет избежать ненужного копирования данных до момента их изменения.

ArraySlice позволяет работать с подмножеством элементов массива без их копирования, что экономит память и время.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41
Разбираемся с existential container в Swift

Existential container — это структура данных в Swift, которая хранит значения типов, скрытых за протоколами, и используется для динамического вызова методов и управления жизненным циклом значений.

⚙️ Existential container для non class-constrained типов занимает 5 машинных слов (40 байт) и состоит из 24 байт данных, указателя на метаданные типа и указателя на таблицу свидетельств протокола.

Value witness table (VWT) описывает операции с конкретными типами, включая инициализацию, копирование и уничтожение значений, что позволяет компилятору генерировать соответствующий код для этих операций.

❗️ В отличие от дженериков, которые используют статическую диспетчеризацию, existential container применяет динамическую диспетчеризацию, что требует выделения памяти в куче для значений больше 3 байт.

✔️ Рекомендуется использовать дженерики по умолчанию, если нет необходимости в динамическом определении типа, чтобы избежать излишнего использования памяти и увеличения размера бинарного файла.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4😁1
How to Use OptionSet in Swift with code samples

ℹ️ OptionSet — это протокол в Swift, который представляет опции в виде битов, позволяя комбинировать несколько значений и выполнять операции, такие как объединение и пересечение.

🖥 В примере кода создается структура TasksListOptions, которая использует OptionSet для определения опций отображения задач, таких как фильтр, поиск и сортировка.

struct TasksListOptions: OptionSet {
let rawValue: Int

static let showFilter = TasksListOptions(rawValue: 1 << 0)
static let showSearch = TasksListOptions(rawValue: 1 << 1)
static let showSort = TasksListOptions(rawValue: 1 << 2)
static let showLayoutSelector = TasksListOptions(rawValue: 1 << 3)
}


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

✔️ OptionSet является предпочтительным инструментом для конфигурации функций, стилей или разрешений в Swift, обеспечивая компактность и производительность.
Please open Telegram to view this post
VIEW IN TELEGRAM
5
Using Observations to observe @Observable model properties

🆕 С Xcode 26 и Swift 6.2 появилась возможность использовать объект Observations для наблюдения за свойствами моделей @Observable, что упрощает процесс наблюдения вне SwiftUI.

🔍 Объект Observations позволяет создать AsyncSequence, который будет эмитировать значения при изменении наблюдаемых свойств, таких как count в модели Counter.

❗️ Важно использовать [weak self] в замыкании Observations, чтобы избежать циклов удержания, что может привести к утечкам памяти.

⚠️ При использовании Observations можно пропустить значения, если они производятся быстрее, чем вы их обрабатываете, поэтому рекомендуется реализовать собственное буферизование.

➡️ Новая система Observations предлагает did set semantics, в отличие от withObservationTracking, который использует will set semantics, что улучшает реакцию на изменения.

@Observable 
class Counter {
var count: Int
}

class CounterObserver {
let counter: Counter

init(counter: Counter) {
self.counter = counter
}

func observe() {
Task { [weak self] in
let values = Observations { [weak self] in
guard let self else { return 0 }
return self.counter.count
}

for await value in values {
guard let self else { break }
print("counter.count: \(value)")
}
}
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
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
2