Swift | Вопросы собесов
الذهاب إلى القناة على Telegram
Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @easyoffer_adv
إظهار المزيد2 181
المشتركون
-324 ساعات
-27 أيام
-1430 أيام
جاري تحميل البيانات...
القنوات المماثلة
سحابة العلامات
الإشارات الواردة والصادرة
---
---
---
---
---
---
جذب المشتركين
أغسطس '26
أغسطس '26
+24
في 0 قنوات
يوليو '26
+18
في 0 قنوات
Get PRO
يونيو '26
+32
في 1 قنوات
Get PRO
مايو '26
+21
في 0 قنوات
Get PRO
أبريل '26
+23
في 0 قنوات
Get PRO
مارس '26
+35
في 0 قنوات
Get PRO
فبراير '26
+45
في 1 قنوات
Get PRO
يناير '26
+58
في 0 قنوات
Get PRO
ديسمبر '25
+28
في 0 قنوات
Get PRO
نوفمبر '25
+156
في 1 قنوات
Get PRO
أكتوبر '25
+26
في 0 قنوات
Get PRO
سبتمبر '25
+41
في 0 قنوات
Get PRO
أغسطس '25
+38
في 0 قنوات
Get PRO
يوليو '25
+27
في 0 قنوات
Get PRO
يونيو '25
+34
في 0 قنوات
Get PRO
مايو '25
+50
في 0 قنوات
Get PRO
أبريل '25
+87
في 0 قنوات
Get PRO
مارس '25
+151
في 2 قنوات
Get PRO
فبراير '25
+123
في 1 قنوات
Get PRO
يناير '25
+127
في 53 قنوات
Get PRO
ديسمبر '24
+55
في 1 قنوات
Get PRO
نوفمبر '24
+75
في 0 قنوات
Get PRO
أكتوبر '24
+193
في 42 قنوات
Get PRO
سبتمبر '24
+348
في 251 قنوات
Get PRO
أغسطس '24
+98
في 0 قنوات
Get PRO
يوليو '24
+140
في 54 قنوات
Get PRO
يونيو '24
+411
في 244 قنوات
Get PRO
مايو '24
+646
في 191 قنوات
Get PRO
أبريل '24
+353
في 23 قنوات
| التاريخ | نمو المشتركين | الإشارات | القنوات | |
| 30 أغسطس | +1 | |||
| 29 أغسطس | 0 | |||
| 28 أغسطس | 0 | |||
| 27 أغسطس | +4 | |||
| 26 أغسطس | +1 | |||
| 25 أغسطس | 0 | |||
| 24 أغسطس | +3 | |||
| 23 أغسطس | 0 | |||
| 22 أغسطس | +2 | |||
| 21 أغسطس | 0 | |||
| 20 أغسطس | 0 | |||
| 19 أغسطس | +1 | |||
| 18 أغسطس | 0 | |||
| 17 أغسطس | +2 | |||
| 16 أغسطس | 0 | |||
| 15 أغسطس | 0 | |||
| 14 أغسطس | +2 | |||
| 13 أغسطس | +1 | |||
| 12 أغسطس | +1 | |||
| 11 أغسطس | 0 | |||
| 10 أغسطس | 0 | |||
| 09 أغسطس | 0 | |||
| 08 أغسطس | 0 | |||
| 07 أغسطس | +1 | |||
| 06 أغسطس | 0 | |||
| 05 أغسطس | +2 | |||
| 04 أغسطس | +2 | |||
| 03 أغسطس | 0 | |||
| 02 أغسطس | +1 | |||
| 01 أغسطس | 0 |
منشورات القناة
🤔 Как решить проблему race condition?
Race condition — это ошибка, возникающая при одновременном доступе нескольких потоков к одним и тем же данным без должной синхронизации. Для решения проблемы race condition в Swift используются механизмы синхронизации, такие как блокировки (locks), семафоры или серийные очереди GCD. Эти инструменты позволяют ограничить доступ к общим ресурсам, чтобы только один поток мог их изменять в любой момент времени. Это предотвращает непредсказуемое поведение программы и ошибки при многопоточном доступе к данным.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
| 2 | 🤔 Какой путь проделывает ивент , когда пользователь нажимает на приложение?
Когда пользователь нажимает на иконку приложения на домашнем экране, iOS проходит несколько этапов перед тем, как приложение становится активным.
🚩Разберём путь события подробнее
🟠Пользователь нажимает на иконку (SpringBoard)
iOS-устройства управляются системой SpringBoard – это оболочка, отвечающая за домашний экран, иконки, фоновые процессы.
Когда пользователь тапает на иконку приложения, SpringBoard отправляет событие UIApplicationLaunchOptionsKey в систему.
🟠iOS загружает процесс приложения
Если приложение не запущено:
- iOS создаёт новый процесс и выделяет память.
- Загружаются зависимости (библиотеки, фреймворки).
- Создаётся объект UIApplication.
🟠Вызывается `application(_:didFinishLaunchingWithOptions:)`
Здесь приложение инициализируется и загружается основной UI.
Метод в AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
print("Приложение запущено")
return true
}
Ставь 👍 и забирай 📚 Базу знаний | 137 |
| 3 | 🤔 Счётчик ссылок дошёл до нуля — в какой момент удалим объект?
Как только счётчик ссылок объекта становится равным нулю, ARC немедленно освобождает память. Удаление происходит автоматически в этот момент, и вызывается деинициализатор (deinit), если он реализован.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний | 156 |
| 4 | 🤔 Что такое gitflow?
В основе Git Flow – несколько веток с разными ролями, чтобы команда могла параллельно разрабатывать новые фичи, исправлять баги и выпускать релизы.
🚩Как работает Git Flow?
🟠Основные ветки (`main` и `develop`)
- main – содержит только стабильные версии.
- develop – основная ветка разработки, в неё вливаются все новые фичи.
🟠Разработка новых фич (feature branches)
- Каждая новая фича создаётся в отдельной ветке feature/*.
- После завершения сливается в develop.
git checkout develop
git checkout -b feature/new-cool-feature
# Разработка...
git checkout develop
git merge feature/new-cool-feature
git branch -d feature/new-cool-feature
🟠Подготовка к релизу (release branches)
- Когда код стабилен, создаётся ветка release/* от develop.
- Здесь можно тестировать и исправлять баги.
- После финального теста сливается в main и develop.
git checkout develop
git checkout -b release/1.0
# Фиксим баги, тестируем...
git checkout main
git merge release/1.0
git tag -a v1.0 -m "Release 1.0"
git checkout develop
git merge release/1.0
git branch -d release/1.0
🟠Горячие фиксы (hotfix branches)
- Если критический баг в main, создаём hotfix/*.
- После исправления вливаем в main и в develop.
git checkout main
git checkout -b hotfix/urgent-bugfix
# Фиксим баг...
git checkout main
git merge hotfix/urgent-bugfix
git checkout develop
git merge hotfix/urgent-bugfix
git branch -d hotfix/urgent-bugfix
Ставь 👍 и забирай 📚 Базу знаний | 169 |
| 5 | 🤔 Какие есть варианты обезопасить работу с историей images?
Обеспечение безопасности работы с историей изображений в iOS-приложениях может включать несколько уровней защиты:
🟠Контроль доступа к изображениям
- Используйте Privacy Settings (NSPhotoLibraryUsageDescription, NSCameraUsageDescription) для контроля доступа к фотоальбому.
- Для ограниченного доступа в iOS 14+ используйте PHPickerViewController.
let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
if status == .authorized {
// Доступ есть
} else {
// Запросить разрешение
PHPhotoLibrary.requestAuthorization { newStatus in
if newStatus == .authorized {
print("Доступ получен")
}
}
}
🟠Шифрование изображений
- Если изображения сохраняются локально, используйте AES-шифрование.
- Можно хранить ключ в Keychain или использовать Secure Enclave.
import CommonCrypto
func encryptImage(data: Data, key: Data) -> Data? {
var buffer = Data(count: data.count + kCCBlockSizeAES128)
var numBytesEncrypted: size_t = 0
let status = CCCrypt(
CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES),
CCOptions(kCCOptionPKCS7Padding), key.bytes, key.count,
nil, data.bytes, data.count, &buffer, buffer.count, &numBytesEncrypted
)
return status == kCCSuccess ? buffer.prefix(numBytesEncrypted) : nil
}
🟠Безопасное хранение изображений
Core Data с Encrypted Store – можно использовать зашифрованные базы данных, такие как SQLCipher.
FileManager + Data Protection – файлы можно хранить в Application Support с флагом .completeFileProtection.
Keychain – если нужно хранить ссылки на изображения или ключи.
let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("secure_image.jpg")
try? imageData.write(to: fileURL, options: .completeFileProtection)
🟠Ограничение кеширования изображений
- Если изображение чувствительное, отключите кеширование в URLSession:
let config = URLSessionConfiguration.default
config.urlCache = nil // Отключаем кеш
let session = URLSession(configuration: config)
🟠Защита от утечек в памяти
- Убедитесь, что ссылки на изображения не создают retain cycle.
- Используйте weak ссылки в кэше изображений.
class ImageCache {
private let cache = NSCache<NSString, UIImage>()
func store(image: UIImage, forKey key: String) {
cache.setObject(image, forKey: key as NSString)
}
func retrieve(forKey key: String) -> UIImage? {
return cache.object(forKey: key as NSString)
}
}
🟠Безопасная загрузка изображений (защита от MITM)
- Используйте HTTPS вместо HTTP.
- Включите App Transport Security (ATS) в Info.plist.
- Верифицируйте SSL-сертификаты при загрузке.
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if let serverTrust = challenge.protectionSpace.serverTrust {
let credential = URLCredential(trust: serverTrust)
completionHandler(.useCredential, credential)
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
Ставь 👍 и забирай 📚 Базу знаний | 152 |
| 6 | 🤔 Что будет, если применить модификатор к View?
SwiftUI создаст новую View с измененными параметрами, не изменяя оригинальный объект. Это позволяет оптимизировать ререндеринг, так как фреймворк пересоздает только измененные элементы.
Благодаря иммутабельности View-дерева, SwiftUI автоматически сравнивает изменения (diffing), обновляя только те части интерфейса, которые изменились. Это делает рендеринг быстрым и эффективным.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний | 165 |
| 7 | 🤔 Перечислите все ленивые (lazy) контейнеры/вью?
В iOS существует несколько ленивых (lazy) контейнеров и вью, которые откладывают создание или загрузку элементов до момента их фактического использования.
🚩`lazy var` (ленивые свойства)
Обычное свойство инициализируется сразу, а lazy – только при первом вызове.
class Example {
lazy var expensiveObject: Data = {
print("Объект создан!")
return Data()
}()
}
let obj = Example()
print("Объект ещё не создан")
_ = obj.expensiveObject // Только теперь создастся
🚩`LazySequence` и `LazyCollection`
Если вы хотите избежать лишних вычислений, можно использовать ленивую последовательность:
let numbers = (1...1000).lazy.map { $0 * 2 } // Не вычисляется сразу!
print(numbers.first!) // Только теперь вычисляется первый элемент
🚩`LazyVStack`, `LazyHStack`, `LazyGrid` (SwiftUI)
В отличие от обычных VStack и HStack, ленивые версии создают элементы только при прокрутке.
ScrollView {
LazyVStack {
ForEach(0..<1000) { index in
Text("Элемент \(index)")
}
}
}
🚩`UITableView` и `UICollectionView` (UIKit)
Они работают по принципу переиспользования ячеек, загружая их только когда нужно.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = "Строка \(indexPath.row)"
return cell
}
Ставь 👍 и забирай 📚 Базу знаний | 187 |
| 8 | 🤔 Что такое static в Swift?
static — ключевое слово, обозначающее, что свойство или метод относится к типу, а не к экземпляру. В классах также используется class для переопределяемых методов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний | 203 |
| 9 | 🤔 Какие объекты участвуют в зависимостях?
В зависимости от контекста, под "объектами, участвующими в зависимостях" можно понимать различные концепции. В программировании под зависимостями чаще всего подразумеваются связи между объектами или модулями, где один объект зависит от другого для выполнения своих функций.
🚩Объект-зависимый и объект-зависимость
Когда один объект (например, ViewController) зависит от другого (NetworkManager), первый становится клиентом, а второй – зависимостью.
class NetworkManager {
func fetchData() {
print("Данные загружены")
}
}
class ViewController {
let networkManager: NetworkManager
init(networkManager: NetworkManager) {
self.networkManager = networkManager
}
func loadData() {
networkManager.fetchData()
}
}
🚩Протоколы как способ ослабления зависимостей
Жесткие зависимости можно ослабить, используя протоколы.
protocol NetworkService {
func fetchData()
}
class NetworkManager: NetworkService {
func fetchData() {
print("Данные загружены")
}
}
class ViewController {
let networkService: NetworkService
init(networkService: NetworkService) {
self.networkService = networkService
}
func loadData() {
networkService.fetchData()
}
}
🚩Зависимости в архитектурах (MVVM, VIPER, DI)
В MVVM зависимость между ViewController и ViewModel.
В VIPER модули зависят друг от друга, но слабо связаны через протоколы.
В DI (Dependency Injection) зависимости передаются снаружи, что повышает тестируемость и гибкость.
🚩Менеджеры зависимостей
Чтобы управлять внешними зависимостями (библиотеками), используются
Swift Package Manager (SPM)
CocoaPods
Carthage
Ставь 👍 и забирай 📚 Базу знаний | 218 |
| 10 | Пожизненный PRO доступ на easyoffer — по цене одного года!
До 2 сентября вы можете купить PRO навсегда.
Покупаешь один раз — пользуешься всю жизнь.
– База вопросов и задач из собеседований
– Примеры видео-ответов на вопросы
– Записи реальных собеседований
– Тренажеры "Проработка вопросов" и "Реальное собеседование"
– Аналитика требований из вакансий
– Автоотклики на вакансии
– Агрегатор вакансий (скоро)
👉 Купить PRO со скидкой 70%: https://easyoffer.ru/pro | 180 |
| 11 | 🤔 Что такое верстка на AutoLayout, а что такое верстка на frame?
- AutoLayout — это система ограничений (constraints), определяющих расположение элементов вне зависимости от размера экрана. Используется при адаптивной, универсальной верстке.
- Frame-верстка — это явное указание координат и размеров каждого элемента. Быстро, но не гибко — плохо масштабируется под разные устройства и ориентации.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний | 199 |
| 12 | 🤔 В каком методе жизненного цикла можно поставить отступы к vue?
Если вы хотите задать отступы (margins, padding) для UIView в жизненном цикле UIViewController, то важно выбрать правильный момент, когда размеры view уже определены.
🚩Пример установки отступов в `viewDidLayoutSubviews()`
class MyViewController: UIViewController {
let myView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
myView.backgroundColor = .red
view.addSubview(myView)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Установка отступов (margins)
myView.frame = view.bounds.insetBy(dx: 20, dy: 50)
}
}
Ставь 👍 и забирай 📚 Базу знаний | 209 |
| 13 | 🤔 Что происходит с классом при компиляции?
При компиляции в Swift класс проходит несколько стадий обработки:
Анализ синтаксиса и семантики – компилятор проверяет код на ошибки.
Генерация промежуточного представления (IR) – создаётся код на уровне LLVM IR.
Оптимизация – Swift применяет различные оптимизации, например, inlining, dead code elimination и другие.
Генерация машинного кода – итоговый код превращается в исполняемый машинный код, специфичный для платформы.
🚩Что конкретно происходит с классом?
В отличие от структур, классы в Swift являются ссылочными типами и хранятся в куче (heap). Это означает, что:
- При создании объекта выделяется память в куче.
- Swift автоматически использует ARC (Automatic Reference Counting) для управления памятью.
- Методы класса могут вызываться через виртуальную таблицу (vtable), если класс использует динамическую диспетчеризацию.
🚩Важные моменты
- Если класс final, компилятор может оптимизировать вызовы методов, убрав динамическую диспетчеризацию.
- Наследование делает вызовы методов менее предсказуемыми (они идут через vtable).
- В отличие от структур, классы не копируются при передаче в функцию, а передаётся ссылка.
class Animal {
var name: String
init(name: String) {
self.name = name
}
func speak() {
print("Some sound")
}
}
final class Dog: Animal {
override func speak() {
print("Woof!")
}
}
let myDog = Dog(name: "Buddy")
myDog.speak()
Ставь 👍 и забирай 📚 Базу знаний | 220 |
| 14 | 🤔 Расскажи про букву D в solid
Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) гласит:
Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций.
Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
🚩Плохой пример (Нарушение DIP)
class MySQLDatabase {
func fetchData() -> String {
return "Данные из MySQL"
}
}
class DataManager {
let database = MySQLDatabase() // Прямая зависимость от MySQL
func getData() -> String {
return database.fetchData()
}
}
🚩Хороший пример (Используем DIP)
Вводим абстракцию (Протокол)
protocol Database {
func fetchData() -> String
}
Реализуем конкретные базы данных
class MySQLDatabase: Database {
func fetchData() -> String {
return "Данные из MySQL"
}
}
class PostgreSQLDatabase: Database {
func fetchData() -> String {
return "Данные из PostgreSQL"
}
}
Используем абстракцию в DataManager
class DataManager {
private let database: Database // Зависимость от абстракции
init(database: Database) {
self.database = database
}
func getData() -> String {
return database.fetchData()
}
}
Использование
let mySQLDataManager = DataManager(database: MySQLDatabase())
print(mySQLDataManager.getData()) // "Данные из MySQL"
let postgreSQLDataManager = DataManager(database: PostgreSQLDatabase())
print(postgreSQLDataManager.getData()) // "Данные из PostgreSQL"
Ставь 👍 и забирай 📚 Базу знаний | 216 |
| 15 | 🤔 Почему по дефолту дабл, а не фолт?
В Swift (и во многих других языках программирования) по умолчанию числовой литерал с плавающей запятой интерпретируется как `Double`, а не Float.
🚩Основные причины:
🟠Бóльшая точность
Double имеет 64 бита, а Float – 32 бита. Это значит, что Double может хранить более точные значения, что особенно важно при математических вычислениях.
🟠Совместимость со стандартными API
Большинство API и стандартных библиотек Swift (например, sin(), cos(), pow()) работают именно с Double.
Например:
let x = 3.14 // По умолчанию это Double
let y = sin(x) // sin() принимает Double
🟠Производительность на современных процессорах
На современных 64-битных процессорах операции с Double выполняются так же быстро или даже быстрее, чем с Float, из-за оптимизаций в аппаратном обеспечении.
🟠Меньше неожиданных ошибок округления
Float может округлять числа с потерей точности, что может привести к неожиданным результатам.
Пример ошибки округления в Float:
let a: Float = 0.1 + 0.2
print(a == 0.3) // false 😱
🚩Как сделать `Float` вручную?
Если всё же нужен Float, надо указать это явно:
let number: Float = 3.14
или
let number = 3.14 as Float
Ставь 👍 и забирай 📚 Базу знаний | 206 |
| 16 | 🤔 Чем отличается garbage collector и подсчет ссылок?
Garbage Collector (GC) и Automatic Reference Counting (ARC) – это два разных подхода к управлению памятью в программировании. Они решают одну задачу: автоматическое освобождение неиспользуемой памяти, но делают это по-разному.
🚩Garbage Collector (GC)
Java, Kotlin, C#, Python, JavaScript
- GC периодически просматривает всю память приложения и ищет объекты, на которые больше нет ссылок.
- Когда такие объекты находятся, они удаляются, а память освобождается.
- Это автоматический процесс, который запускается по мере необходимости.
🚩Подсчет ссылок (ARC - Automatic Reference Counting)
Где используется: Swift, Objective-C
- Каждый объект имеет счетчик ссылок (reference count).
- Когда переменная создает ссылку на объект, счетчик увеличивается.
- Когда переменная перестает ссылаться на объект, счетчик уменьшается.
- Когда счетчик достигает нуля, объект удаляется из памяти сразу же.
class Person {
var pet: Pet?
}
class Pet {
var owner: Person?
}
let person = Person()
let pet = Pet()
person.pet = pet
pet.owner = person // Теперь оба объекта держат друг друга, и ARC их не удалит
Решение – использовать weak:
class Pet {
weak var owner: Person? // Теперь утечки памяти не будет
}
Ставь 👍 и забирай 📚 Базу знаний | 221 |
| 17 | 🤔 Класс open — финальный или нефинальный?
open — всегда нефинальный, то есть разрешает наследование и переопределение. Противоположностью является final, который запрещает всё это.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний | 225 |
| 18 | 🤔 Если обозначить внутри метода Synchronized , что будет монитору?
Это высокоуровневый механизм синхронизации, который объединяет взаимное исключение (mutex) и условные переменные (condition variables) для управления доступом к объектам в многопоточной среде.
🚩Как работает
🟠Взаимное исключение (Mutual Exclusion)
Только один поток может выполнить защищенный блок кода в любой момент времени.
🟠Условные переменные (Condition Variables)
Позволяют потокам ожидать определенных условий, а другим потокам уведомлять их о наступлении этих условий.
🚩Примеры
class ThreadSafeClass {
private var internalState = 0
private let queue = DispatchQueue(label: "com.example.threadSafeQueue")
func increment() {
queue.sync {
internalState += 1
}
}
func getState() -> Int {
return queue.sync {
internalState
}
}
}
С NSLock
class ThreadSafeClass {
private var internalState = 0
private let lock = NSLock()
func increment() {
lock.lock()
internalState += 1
lock.unlock()
}
func getState() -> Int {
lock.lock()
let state = internalState
lock.unlock()
return state
}
}
С objc_sync_enter и objc_sync_exit
class ThreadSafeClass: NSObject {
private var internalState = 0
func increment() {
objc_sync_enter(self)
internalState += 1
objc_sync_exit(self)
}
func getState() -> Int {
objc_sync_enter(self)
let state = internalState
objc_sync_exit(self)
return state
}
}
Ставь 👍 и забирай 📚 Базу знаний | 239 |
| 19 | 🤔 Кто будет управлять нажатием: вложенная коллекция или родительская?
По умолчанию вложенная коллекция перехватывает события. Однако управление можно перенастроить: отключить isUserInteractionEnabled у ячеек, передать события вверх, изменить приоритеты gesture recognizers.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний | 222 |
| 20 | 🤔 Расскажи про механизм отмены в operatsion
В Operation (ранее NSOperation) в Foundation есть встроенный механизм отмены, который позволяет корректно завершить операцию, если она больше не нужна. Однако отмена не прерывает выполнение автоматически – код внутри операции должен сам проверять флаг отмены и корректно завершаться.
🚩Как работает отмена `Operation`?
Вызывается cancel() – операция помечается как отмененная.
Флаг isCancelled становится true, но операция продолжает выполняться, если не проверяет этот флаг.
Операция должна самостоятельно проверять isCancelled и прерываться.
class MyOperation: Operation {
override func main() {
for i in 1...10 {
if isCancelled { return } // Проверяем, отменена ли операция
print("Выполняется шаг \(i)")
sleep(1) // Симуляция работы
}
}
}
let queue = OperationQueue()
let operation = MyOperation()
queue.addOperation(operation)
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
operation.cancel() // Отменяем через 3 секунды
}
🚩Отмена асинхронных операций
Если операция асинхронная (isAsynchronous = true), просто проверять isCancelled недостаточно. Надо корректно управлять состояниями (isExecuting, isFinished).
class AsyncOperation: Operation {
private var _executing = false
private var _finished = false
override var isAsynchronous: Bool { true }
override var isExecuting: Bool {
get { return _executing }
set {
willChangeValue(for: \.isExecuting)
_executing = newValue
didChangeValue(for: \.isExecuting)
}
}
override var isFinished: Bool {
get { return _finished }
set {
willChangeValue(for: \.isFinished)
_finished = newValue
didChangeValue(for: \.isFinished)
}
}
override func start() {
if isCancelled {
isFinished = true
return
}
isExecuting = true
executeTask()
}
private func executeTask() {
DispatchQueue.global().asyncAfter(deadline: .now() + 3) {
if self.isCancelled {
self.complete()
return
}
print("Асинхронная операция завершена")
self.complete()
}
}
private func complete() {
isExecuting = false
isFinished = true
}
}
let queue = OperationQueue()
let asyncOp = AsyncOperation()
queue.addOperation(asyncOp)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
asyncOp.cancel() // Отменяем через 1 секунду
}
🚩Отмена зависимых операций
Если у вас есть зависимости между операциями, отмена одной может автоматически отменить все последующие:
let op1 = MyOperation()
let op2 = MyOperation()
op2.addDependency(op1)
let queue = OperationQueue()
queue.addOperations([op1, op2], waitUntilFinished: false)
// Отменяем первую операцию, вторая тоже не выполнится
op1.cancel()
Ставь 👍 и забирай 📚 Базу знаний | 237 |
