tgindex
Swift | Вопросы собесов

Swift | Вопросы собесов

Статистика

Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @easyoffer_adv

Последний пост
18:11
Последнее чтение
17:13
Постов за неделю
12
Всего постов
28
Тип
открытый
Язык
русский
Категория
Технологии (по похожим)
В каталоге с
13 авг.
Подписчики
2 184
0 за 3 дн.
Сутки
−1
−0,05%
Неделя
 
Месяц
 
Просмотров на пост
225
25 постов
Вовлечённость
10,3%
к подписчикам
Постов в день
1,7
всего 28
Упоминаний
2
каналов
Охват размещения
оценка
1/24сутки в ленте
182
1/48двое суток
208
1/72трое суток
224

Оценка по просмотрам недавних постов: пост набирает почти всё за первые сутки.

Посты

  • видео или голосовое, без подписи

  • 11:0510412

    🤔 Что такое барьеры? Барьер (Barrier) – это механизм синхронизации потоков, который позволяет контролировать порядок выполнения операций** в многопоточной среде. 🚩Барьеры памяти (Memory Barriers) Используются в многопоточном программировании для управления порядком операций с памятью. В многопоточной среде процессоры и компиляторы могут оптимизировать порядок команд, что может привести к непредсказуемому поведению. Барьеры памяти предотвращают это. #include <stdatomic.h> atomic_int sharedValue = 0; void updateValue() { atomic_store_explicit(&sharedValue, 10, memory_order_release); } void readValue() { int value = atomic_load_explicit(&sharedValue, memory_order_acquire); } 🚩Барьеры в GCD (`dispatch_barrier`) Используются в Grand Central Dispatch (GCD)** для контроля порядка выполнения задач в DispatchQueue. - Позволяет блокировать очередь на время выполнения задачи. - Все задачи до барьера выполняются параллельно. - Барьер ждёт завершения всех предыдущих задач, выполняется эксклюзивно, затем разрешает следующие задачи. let queue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent) queue.async { print("Задача 1") } queue.async { print("Задача 2") } // БАРЬЕРНАЯ ОПЕРАЦИЯ queue.async(flags: .barrier) { print("🔴 Барьер: все предыдущие задачи завершены, выполняюсь один!") } queue.async { print("Задача 3") } 🚩Барьеры в OpenMP (Параллельные вычисления) В OpenMP (#pragma omp barrier) ждёт завершения всех потоков перед выполнением следующего кода. #pragma omp parallel { printf("До барьера\n"); #pragma omp barrier printf("После барьера\n"); } Ставь 👍 и забирай 📚 Базу знаний

  • 22:1914411

    🤔 В чём разница между вью и леером? В iOS и macOS приложениях, разработанных с использованием Swift или Objective-C, UIView и CALayer играют ключевые роли в управлении и отображении пользовательского интерфейса. Несмотря на то, что они тесно связаны, между ними есть важные различия. Давайте рассмотрим их подробнее. 🚩UIView UIView — это базовый класс для всех элементов пользовательского интерфейса в iOS. Он представляет собой прямоугольную область на экране, которая может отображать контент и реагировать на события пользователя, такие как нажатия, жесты и касания. UIView предоставляет множество свойств и методов для управления внешним видом, положением и поведением представления. Примеры включают frame, bounds, center, backgroundColor, alpha, isHidden, и subviews. UIView также поддерживает анимации, автолэйаут и работу с событийной системой. UIView обрабатывает пользовательские события, такие как касания и жесты. Он предоставляет методы, такие как touchesBegan, touchesMoved, и touchesEnded, для обработки этих событий. let myView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) myView.backgroundColor = .blue view.addSubview(myView) 🚩CALayer CALayer — это базовый класс для всех графических слоев, используемых в Core Animation. Он обеспечивает низкоуровневую поддержку для рендеринга, анимации и композиции графики. CALayer предоставляет свойства для управления внешним видом, такими как backgroundColor, borderWidth, cornerRadius, shadowOpacity, contents (для отображения изображений), и transform. CALayer также поддерживает анимации, используя ключевые кадры и основные анимации. CALayer не обрабатывает пользовательские события напрямую. Эти задачи оставлены на UIView, который может содержать один или несколько слоев. let myLayer = CALayer() myLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 100) myLayer.backgroundColor = UIColor.blue.cgColor view.layer.addSublayer(myLayer) 🚩Основные различия между UIView и CALayer 🟠По уровеню абстракции UIView — это более высокий уровень абстракции, предназначенный для работы с пользовательским интерфейсом и обработкой событий. CALayer — более низкоуровневый элемент, который фокусируется на рендеринге и анимации графики. 🟠Реакция на события UIView обрабатывает события пользовательского интерфейса. CALayer не обрабатывает события, но предоставляет возможности для рендеринга и анимации. 🟠Иерархия UIView может содержать другие представления (subviews) и управлять их иерархией. CALayer может содержать другие слои (sublayers) и управлять их иерархией. 🟠Анимации UIView использует UIView.animate для создания анимаций, которые высокоуровневые и просты в использовании. CALayer использует CAAnimation и его подклассы для создания анимаций, которые более гибкие и мощные, но требуют большего количества кода. Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Чем отличается garbage collector и подсчёт ссылок (ARC)? - ARC работает сразу, как только счётчик = 0 (детерминированное управление); - GC (в Java, Python) работает фоново, периодически сканируя объекты. Он может задерживать удаление, но справляется с циклами ссылок. ARC не умеет разрывать retain cycle — нужно вручную применять weak. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 Какие объекты участвуют в зависимостях? В зависимости от контекста, под "объектами, участвующими в зависимостях" можно понимать различные концепции. В программировании под зависимостями чаще всего подразумеваются связи между объектами или модулями, где один объект зависит от другого для выполнения своих функций. 🚩Объект-зависимый и объект-зависимость Когда один объект (например, 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 Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 В чём разница между as, as! и as? Эти три оператора связаны с приведением типов: - as используется для безопасного восходящего приведения, когда тип объекта гарантированно может быть приведён к указанному типу (например, суперклассу или протоколу). - as! — это принудительное нисходящее приведение. Оно требует уверенности в типе объекта, иначе приложение упадёт при ошибке. - as? — это безопасное нисходящее приведение, при котором результат будет опционалом. Если приведение невозможно, возвращается nil. Таким образом: - as — безопасно и для "поднятия" вверх по иерархии. - as! — рискованно, используется только если уверен в типе. - as? — гибко и безопасно, но требует работы с опционалом. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 Для каких сущностей работает copy on write? Механизм Copy-on-Write (CoW) используется для оптимизации производительности и использования памяти при копировании объектов. Этот механизм особенно полезен для неизменяемых (immutable) структур данных. CoW часто ассоциируется со стандартными коллекциями и собственными типами данных, реализованными как структуры (value types), такие как Array, String, Dictionary, и Set. 🚩Принцип работы Copy-on-Write Работает так, что копия объекта создаётся только в тот момент, когда происходит попытка модификации. До этого момента все копии объекта фактически ссылаются на одни и те же данные в памяти. Это позволяет сэкономить как время, так и память, поскольку избегается ненужное дублирование данных, когда оно не требуется. 🚩Как это работает в Swift Автоматически применяет механизм CoW к своим стандартным коллекциям, таким как Array, String, Dictionary, и Set. Это означает, что при передаче этих объектов в функции или при их копировании реальное дублирование данных происходит только в случае модификации одной из копий. Таким образом, если вы создаёте копию массива и не изменяете его, обе переменные будут указывать на одни и те же данные в памяти. Как только вы модифицируете одну из копий, Swift создаст реальную копию данных для этой копии, обеспечивая независимость данных между оригиналом и копией. var originalArray = [1, 2, 3] var copiedArray = originalArray // На этом этапе данные не дублируются copiedArray.append(4) // Теперь данные копируются, потому что copiedArray модифицируется Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Какие ещё бывают type? – Int, Double, String, Bool — базовые типы, – struct, class, enum, tuple, – Optional, – Protocol, – Function, – Any, AnyObject, Never. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 Расскажи про механизм отмены в 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() Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Расскажи про capture list? Capture list в замыканиях Swift используется для управления захватом переменных, предотвращая сильные ссылки ([weak self]) или обеспечивая их копирование ([x]). Это помогает управлять памятью и избегать утечек. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 Где могут располагаться стеки помимо структуры В программировании стек (stack) — это структура данных и область памяти, используемая для хранения временных данных. В зависимости от контекста, стек может существовать в нескольких местах. 🟠Стек вызовов (Call Stack) Это главная область памяти в оперативной памяти (RAM), где хранятся: - Локальные переменные функций. - Адреса возврата после завершения функции. - Контекст выполнения программы. func functionA() { functionB() } func functionB() { print("Вызов B") } functionA() func infiniteRecursion() { infiniteRecursion() // ❌ Бесконечный вызов } 🟠Стек в структуре данных (например, `Array`) В Swift можно реализовать стек вручную, используя массив (Array). struct Stack<T> { private var elements: [T] = [] mutating func push(_ item: T) { elements.append(item) } mutating func pop() -> T? { return elements.popLast() } } var stack = Stack<Int>() stack.push(10) stack.push(20) print(stack.pop()!) // 20 🟠Потоковый стек (Thread Stack) Каждый поток (Thread) в многопоточном программировании получает свой стек. DispatchQueue.global().async { print("Фоновый поток") } print("Главный поток") 🟠Стек в автоматическом управлении памятью (ARC) Swift использует Automatic Reference Counting (ARC) для управления памятью. Когда объект больше не нужен, он удаляется из памяти (в том числе из стека). func createPerson() { let person = "Иван" // Создаётся в стеке print(person) } createPerson() // Переменная person удаляется при выходе из функции Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 В каких моментах жизненного цикла лучше поместить подписку? Подписку на уведомления (NotificationCenter), KVO или Combine в жизненном цикле UIViewController лучше размещать в методах, где гарантируется её актуальность и корректное удаление. 🟠Подписка в `viewDidLoad()` Подписка на события обычно происходит в `viewDidLoad()`, так как этот метод вызывается один раз при создании контроллера. override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver( self, selector: #selector(handleNotification), name: .someNotification, object: nil ) } @objc func handleNotification(_ notification: Notification) { print("Получено уведомление") } 🟠Подписка в `viewWillAppear()` – если уведомления нужны только при отображении экрана Если подписка должна работать только когда экран на экране, используем viewWillAppear(). var cancellable: AnyCancellable? override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) cancellable = NotificationCenter.default.publisher(for: .someNotification) .sink { _ in print("Событие получено") } } 🟠`viewWillDisappear()` – отписка от событий Когда контроллер скрывается, подписки можно удалить, чтобы избежать ненужных вызовов. Удаление подписки на NotificationCenter: override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self, name: .someNotification, object: nil) } Удаление Combine подписки (cancellable) override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) cancellable?.cancel() cancellable = nil } 🟠`deinit` – отписка, если подписка создаётся в `viewDidLoad()` Если подписка работает на протяжении всего жизненного цикла контроллера, её можно удалить в `deinit`. deinit { NotificationCenter.default.removeObserver(self) } Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Какие есть известные проблемы с многопоточностью? Известные проблемы с многопоточностью включают гонки данных, блокировки и взаимоблокировки (deadlocks). Гонки данных происходят, когда несколько потоков одновременно пытаются изменить одни и те же данные без должной синхронизации. Блокировки возникают, когда потоки ждут освобождения ресурсов друг от друга, что замедляет работу программы. Взаимоблокировки случаются, когда два потока захватывают ресурсы и не могут завершить работу из-за зависимостей. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 Что происходит с классом при компиляции? При компиляции в 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() Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Какие есть инструменты для работы с потоками? В Swift есть несколько инструментов для работы с многопоточностью и параллельным выполнением кода. Вот основные из них: 🟠GCD (Grand Central Dispatch) – главный инструмент для потоков GCD – это низкоуровневая технология, позволяющая управлять задачами (тасками) в очередях (DispatchQueue). DispatchQueue.global(qos: .background).async { print("Фоновый поток") DispatchQueue.main.async { print("Вернулись в главный поток") } } 🟠OperationQueue – более удобный API для задач OperationQueue – это более гибкая и объектно-ориентированная альтернатива GCD. let queue = OperationQueue() queue.maxConcurrentOperationCount = 2 // Ограничение на 2 задачи одновременно queue.addOperation { print("Операция 1") } queue.addOperation { print("Операция 2") } 🟠Actors – безопасная работа с потоками в Swift 5.5+ С actor можно работать с потоками без гонок данных, потому что все его свойства защищены от одновременного доступа. actor Counter { private var value = 0 func increment() { value += 1 } func getValue() -> Int { return value } } let counter = Counter() Task { await counter.increment() print(await counter.getValue()) // Потокобезопасный доступ } 🟠Task & Async/Await (Swift 5.5+) – современный подход к асинхронности С async/await код становится читаемым и удобным. func fetchData() async -> String { try? await Task.sleep(nanoseconds: 1_000_000_000) // 1 секунда задержки return "Данные загружены" } Task { let result = await fetchData() print(result) } Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Что нужно сделать, чтобы кастомная структура стала ключом в dictionary? В Swift ключи в словаре (Dictionary) должны быть уникальными и сравниваться между собой. Поэтому, если вы хотите использовать*свою структуру в качестве ключа, она должна соответствовать протоколу Hashable. 🚩Что нужно? Структура должна соответствовать Hashable Должен быть реализован hash(into:) или использовать Equatable + Hashable автоматически Свойства структуры должны быть Hashable (если String, Int, Double – все ок) 🚩Пример кастомной структуры в `Dictionary` struct Person: Hashable { let id: Int let name: String } // Теперь можно использовать `Person` как ключ var peopleAges: [Person: Int] = [ Person(id: 1, name: "Alice"): 25, Person(id: 2, name: "Bob"): 30 ] // Доступ по ключу let alice = Person(id: 1, name: "Alice") print(peopleAges[alice] ?? "Не найдено") // 25 🚩Ручная реализация `hash(into:)` Если нужно кастомное хеширование, можно реализовать hash(into:): struct Person: Hashable { let id: Int let name: String func hash(into hasher: inout Hasher) { hasher.combine(id) // Используем только id для хеша } } Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Как устроено наследование? Это ключевой механизм ООП, позволяющий классам наследовать свойства, методы и другие характеристики от других классов. Это позволяет создавать новые классы на основе существующих, расширяя их функциональность или изменяя её. 🚩Основы наследования 🟠Определение базового класса Базовый класс определяет общие свойства и методы, которые могут быть унаследованы подклассами. 🟠Создание подкласса Подкласс наследует (или "расширяет") базовый класс. Он может переопределять унаследованные методы и свойства, добавлять новые методы и свойства, а также добавлять инициализаторы или изменять существующие. 🟠Переопределение методов и свойств Подклассы могут переопределять методы, свойства и индексаторы базового класса для изменения или расширения их поведения. 🟠Предотвращение переопределения Можно предотвратить переопределение методов, свойств или индексаторов с помощью ключевого слова final. Если метод, свойство или индексатор объявлен как final, то он не может быть переопределён в подклассе. class Vehicle { var currentSpeed = 0.0 var description: String { return "traveling at \(currentSpeed) miles per hour" } func makeNoise() { // Этот метод будет переопределен в подклассах, если необходимо } } class Bicycle: Vehicle { var hasBasket = false } class Car: Vehicle { var gear = 1 final func drive() { print("Car is moving") } override func makeNoise() { print("Vroom!") } } 🚩Использование super Подклассы могут вызывать методы своего суперкласса с помощью ключевого слова super. Это позволяет подклассам расширять, а не заменять поведение суперкласса. Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 Как остановить подписку, когда пользователь не видит экран? Подписку следует удалить в момент, когда экран становится невидимым: - В UIKit: viewWillDisappear или viewDidDisappear. - В SwiftUI: onDisappear. Также важно: - Для Combine использовать AnyCancellable и занулять его (cancellable = nil). - В RxSwift — использовать disposeBag или вручную вызывать dispose(). Это предотвращает утечки памяти и ненужную работу подписки в фоне. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

  • 🤔 Чем опасна утечка памяти? Утечка памяти (memory leak) – это ситуация, когда память остаётся выделенной, но больше не используется программой и не освобождается. class Person { var pet: Pet? deinit { print("Person удалён") } } class Pet { var owner: Person? deinit { print("Pet удалён") } } var person: Person? = Person() var pet: Pet? = Pet() person?.pet = pet pet?.owner = person person = nil pet = nil 🚩Как избежать утечек памяти? 🟠Использовать `weak` или `unowned` ссылки Слабые (weak) или безвладельческие (unowned) ссылки не увеличивают счётчик ссылок, что разрывает цикл. class Person { var pet: Pet? deinit { print("Person удалён") } } class Pet { weak var owner: Person? // Слабая ссылка deinit { print("Pet удалён") } } var person: Person? = Person() var pet: Pet? = Pet() person?.pet = pet pet?.owner = person person = nil // "Person удалён" pet = nil // "Pet удалён" 🟠Использовать `unowned`, если объект всегда будет существовать unowned похож на weak, но он не может быть `nil`. class Owner { var car: Car? deinit { print("Owner удалён") } } class Car { unowned var owner: Owner // Безвладельческая ссылка init(owner: Owner) { self.owner = owner } deinit { print("Car удалён") } } var owner: Owner? = Owner() owner?.car = Car(owner: owner!) owner = nil // "Owner удалён", "Car удалён" 🟠Разрывать циклы в замыканиях (`[weak self]`) Замыкания захватывают объекты, создавая циклические ссылки. Проблема: self удерживается замыканием class ViewController { var closure: (() -> Void)? func setup() { closure = { print(self) // Удерживает self, создавая цикл! } } deinit { print("ViewController удалён") } } var vc: ViewController? = ViewController() vc?.setup() vc = nil // ❌ "ViewController" НЕ удалится 🚩Как найти утечки памяти? 🟠Использовать `Instrument – Leaks` в Xcode - Открываем Xcode > Product > Profile. - Выбираем Leaks. - Запускаем приложение и проверяем, остаются ли объекты в памяти. 🟠Проверить `deinit` Если метод deinit не вызывается – значит, объект утёк в память. class Test { deinit { print("Test удалён") } } var obj: Test? = Test() obj = nil // Должно напечатать "Test удалён" 🟠Включить `Malloc Stack Logging` - В Xcode открываем "Debug Memory Graph" (нажимая значок в Debugger). - Смотрим, какие объекты остались в памяти. Ставь 👍 и забирай 📚 Базу знаний

  • 🤔 В чем проблема, если все переменные будут делаться в вик? Если все переменные в коде сделать weak, объекты могут мгновенно удаляться из памяти, потому что никто не будет владеть ими (strong reference). 🚩Как работает `weak`? - weak создает слабую ссылку – объект не увеличивает счетчик ссылок (retain count). - Если нет других (strong) ссылок на объект, он удаляется (ARC освобождает память). - weak переменные всегда являются Optional, потому что объект может стать nil в любой момент. class Person { weak var name: String? // ❌ Ошибка! Строки – это value type, weak нельзя } Проблема, если weak используется везде class Car { weak var model: String? // ❌ Ошибка (value type) weak var owner: Person? // ⚠️ Будет nil, если нет других strong ссылок } class Person { var car: Car? } var person: Person? = Person() person?.car = Car() person?.car?.owner = person // ❌ `owner` - weak, объект сразу удалится print(person?.car?.owner) // nil, объект Person уничтожен 🚩Когда `weak` полезен? 🟠Избегание циклов ссылок (retain cycle) Например, между delegate и ViewController protocol SomeDelegate: AnyObject { func doSomething() } class ViewController { weak var delegate: SomeDelegate? // ✅ Prevent retain cycle } 🟠Когда объект не должен владеть другим объектом Например, ячейки в UITableView не должны владеть ViewController. Ставь 👍 и забирай 📚 Базу знаний

Swift | Вопросы собесов — tgindex