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

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

رفتن به کانال در Telegram

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

نمایش بیشتر
2 184
مشترکین
اطلاعاتی وجود ندارد24 ساعت
اطلاعاتی وجود ندارد7 روز
-1230 روز
جذب مشترکین
اوت '26
اوت '26
+19
در 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 کانال‌ها
تاریخ
رشد مشترکین
اشارات
کانال‌ها
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
پست‌های کانال
🤔 Что такое static в Swift? static — ключевое слово, обозначающее, что свойство или метод относится к типу, а не к экземпляру. В классах также используется class для переопределяемых методов. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

2
🤔 Какие объекты участвуют в зависимостях? В зависимости от контекста, под "объектами, участвующими в зависимостях" можно понимать различные концепции. В программировании под зависимостями чаще всего подразумеваются связи между объектами или модулями, где один объект зависит от другого для выполнения своих функций. 🚩Объект-зависимый и объект-зависимость Когда один объект (например, 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 Ставь 👍 и забирай 📚 Базу знаний
158
3
Пожизненный PRO доступ на easyoffer — по цене одного года! До 2 сентября вы можете купить PRO навсегда. Покупаешь один раз — пользуешься всю жизнь. – База вопросов и задач из собеседований – Примеры видео-ответов на вопросы – Записи реальных собеседований – Тренажеры "Проработка вопросов" и "Реальное собеседование" – Аналитика требований из вакансий – Автоотклики на вакансии – Агрегатор вакансий (скоро) 👉 Купить PRO со скидкой 70%: https://easyoffer.ru/pro
166
4
🤔 Что такое верстка на AutoLayout, а что такое верстка на frame? - AutoLayout — это система ограничений (constraints), определяющих расположение элементов вне зависимости от размера экрана. Используется при адаптивной, универсальной верстке. - Frame-верстка — это явное указание координат и размеров каждого элемента. Быстро, но не гибко — плохо масштабируется под разные устройства и ориентации. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
171
5
🤔 В каком методе жизненного цикла можно поставить отступы к 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) } } Ставь 👍 и забирай 📚 Базу знаний
186
6
🤔 Что происходит с классом при компиляции? При компиляции в 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() Ставь 👍 и забирай 📚 Базу знаний
196
7
🤔 Расскажи про букву 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" Ставь 👍 и забирай 📚 Базу знаний
203
8
🤔 Почему по дефолту дабл, а не фолт? В 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 Ставь 👍 и забирай 📚 Базу знаний
199
9
🤔 Чем отличается 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? // Теперь утечки памяти не будет } Ставь 👍 и забирай 📚 Базу знаний
213
10
🤔 Класс open — финальный или нефинальный? open — всегда нефинальный, то есть разрешает наследование и переопределение. Противоположностью является final, который запрещает всё это. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
217
11
🤔 Если обозначить внутри метода 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 } } Ставь 👍 и забирай 📚 Базу знаний
226
12
🤔 Кто будет управлять нажатием: вложенная коллекция или родительская? По умолчанию вложенная коллекция перехватывает события. Однако управление можно перенастроить: отключить isUserInteractionEnabled у ячеек, передать события вверх, изменить приоритеты gesture recognizers. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
207
13
🤔 Расскажи про механизм отмены в 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() Ставь 👍 и забирай 📚 Базу знаний
221
14
🤔 Когда начинает работать динамическая диспетчеризация? Динамическая диспетчеризация происходит во время выполнения, когда метод вызывается через объект. Она используется Objective-C runtime для выбора метода, который будет вызван. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
214
15
🤔 Как устроена память? Память устройства можно представить в виде нескольких уровней, каждый из которых имеет свою скорость доступа, размер и назначение: 🟠Регистры процессора Это самая быстрая память, непосредственно встроенная в процессор. Регистры хранят те данные, с которыми процессор работает в данный момент времени. 🟠Кэш-память Она находится непосредственно на процессоре или рядом с ним. Кэш-память используется для временного хранения копий часто используемых данных из основной памяти для ускорения доступа к ним. Кэш-память делится на несколько уровней (L1, L2, и иногда L3), где L1 — самый быстрый и обычно самый маленький. 🟠Оперативная память (ОЗУ) Здесь хранятся данные и программы, с которыми компьютер работает в данный момент. Доступ к ОЗУ быстрый, но оно является временным хранилищем: при выключении устройства данные в ОЗУ теряются. 🟠Постоянная память (ПЗУ, SSD, HDD) Это память для долговременного хранения данных. Она сохраняет информацию даже при выключении питания. HDD (жесткие диски) использовались ранее и работают на принципе магнитного записывания данных, в то время как SSD (твердотельные накопители) работают на основе флеш-памяти и обеспечивают более быстрый доступ к данным. 🟠Виртуальная память Это техника, которая позволяет операционной системе использовать часть жесткого диска (или SSD) как дополнительную оперативную память. Когда ОЗУ заполнено, операционная система может перемещать редко используемые данные из ОЗУ на диск в специальный файл подкачки (swap file), освобождая ОЗУ для других задач. Ставь 👍 и забирай 📚 Базу знаний
245
16
🤔 Зачем нужен оператор future? Если речь о Future в Swift Combine — он представляет одноразовое асинхронное событие, которое может завершиться значением или ошибкой. Используется для интеграции старого кода в реактивную модель. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
237
17
🤔 Какие изменения надо сделать в constrait перед вызовом layout? Перед вызовом layoutIfNeeded() или layoutSubviews() в iOS-приложении, нужно изменить значение констрейнта и вызвать анимацию, если необходимо. Вот основные шаги: 🟠Обновление значения констрейнта Перед вызовом layoutIfNeeded(), измените свойство констрейнта (например, constant у NSLayoutConstraint). class ViewController: UIViewController { @IBOutlet weak var button: UIButton! @IBOutlet weak var heightConstraint: NSLayoutConstraint! override func viewDidLoad() { super.viewDidLoad() DispatchQueue.main.asyncAfter(deadline: .now() + 2) { self.changeButtonHeight() } } func changeButtonHeight() { heightConstraint.constant = 100 // Меняем значение констрейнта UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() // Перестраиваем макет } } } 🟠Если меняется набор констрейнтов Если нужно удалить/добавить констрейнты, используйте `activate()` / `deactivate()`. var expanded = false @IBOutlet weak var smallHeightConstraint: NSLayoutConstraint! @IBOutlet weak var largeHeightConstraint: NSLayoutConstraint! func toggleHeight() { expanded.toggle() if expanded { NSLayoutConstraint.deactivate([smallHeightConstraint]) NSLayoutConstraint.activate([largeHeightConstraint]) } else { NSLayoutConstraint.deactivate([largeHeightConstraint]) NSLayoutConstraint.activate([smallHeightConstraint]) } UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } } 🟠Если работа идёт в `viewDidLoad()` Во viewDidLoad() элементы ещё не отрисованы, поэтому layoutIfNeeded() не сработает. Используйте viewDidAppear() или вызовите layoutIfNeeded() после view.layoutIfNeeded(). override func viewDidLoad() { super.viewDidLoad() heightConstraint.constant = 100 view.layoutIfNeeded() // НЕ обновит макет, потому что он ещё не загружен } Решение override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) heightConstraint.constant = 100 UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } } Разница между layoutIfNeeded() и setNeedsLayout() heightConstraint.constant = 100 view.setNeedsLayout() // Обновление произойдет на следующем цикле рендера Ставь 👍 и забирай 📚 Базу знаний
258
18
🤔 Наследником чего является UIWindow? UIWindow наследуется от UIView, а значит, участвует в иерархии отображения. Она представляет основное окно, в котором располагаются все видимые элементы приложения. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
226
19
🤔 Что такое барьеры? Барьер (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"); } Ставь 👍 и забирай 📚 Базу знаний
255
20
🤔 В чём разница между вью и леером? В 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 и его подклассы для создания анимаций, которые более гибкие и мощные, но требуют большего количества кода. Ставь 👍 и забирай 📚 Базу знаний
232