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

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

Open in Telegram

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

Show more
2 184
Subscribers
No data24 hours
No data7 days
-1230 days
Posts Archive
🤔 Перечислите все ленивые (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
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое static в Swift? static — ключевое слово, обозначающее, что свойство или метод относится к типу, а не к экземпляру. В классах также используется class для переопределяемых методов. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

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

Пожизненный PRO доступ на easyoffer — по цене одного года! До 2 сентября вы можете купить PRO навсегда. Покупаешь один раз — пользуешься всю жизнь. – База вопросов и задач из собеседований – Примеры видео-ответов на вопросы – Записи реальных собеседований – Тренажеры "Проработка вопросов" и "Реальное собеседование" – Аналитика требований из вакансий – Автоотклики на вакансии – Агрегатор вакансий (скоро) 👉 Купить PRO со скидкой 70%: https://easyoffer.ru/pro

🤔 Что такое верстка на AutoLayout, а что такое верстка на frame? - AutoLayout — это система ограничений (constraints), определяющих расположение элементов вне зависимости от размера экрана. Используется при адаптивной, универсальной верстке. - Frame-верстка — это явное указание координат и размеров каждого элемента. Быстро, но не гибко — плохо масштабируется под разные устройства и ориентации. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 В каком методе жизненного цикла можно поставить отступы к 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)
    }
}
Ставь 👍 и забирай 📚 Базу знаний

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

🤔 Расскажи про букву 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"
Ставь 👍 и забирай 📚 Базу знаний

🤔 Почему по дефолту дабл, а не фолт? В Swift (и во многих других языках программирования) по умолчанию числовой литерал с плавающей запятой интерпретируется как `Double`, а не Float. 🚩Основные причины: 🟠Бóльшая точность Double имеет 64 бита, а Float32 бита. Это значит, что 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
Ставь 👍 и забирай 📚 Базу знаний

🤔 Чем отличается 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? // Теперь утечки памяти не будет
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Класс open — финальный или нефинальный? open — всегда нефинальный, то есть разрешает наследование и переопределение. Противоположностью является final, который запрещает всё это. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Если обозначить внутри метода 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
    }
}
Ставь 👍 и забирай 📚 Базу знаний

🤔 Кто будет управлять нажатием: вложенная коллекция или родительская? По умолчанию вложенная коллекция перехватывает события. Однако управление можно перенастроить: отключить isUserInteractionEnabled у ячеек, передать события вверх, изменить приоритеты gesture recognizers. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

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

🤔 Когда начинает работать динамическая диспетчеризация? Динамическая диспетчеризация происходит во время выполнения, когда метод вызывается через объект. Она используется Objective-C runtime для выбора метода, который будет вызван. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Как устроена память? Память устройства можно представить в виде нескольких уровней, каждый из которых имеет свою скорость доступа, размер и назначение: 🟠Регистры процессора Это самая быстрая память, непосредственно встроенная в процессор. Регистры хранят те данные, с которыми процессор работает в данный момент времени. 🟠Кэш-память Она находится непосредственно на процессоре или рядом с ним. Кэш-память используется для временного хранения копий часто используемых данных из основной памяти для ускорения доступа к ним. Кэш-память делится на несколько уровней (L1, L2, и иногда L3), где L1 — самый быстрый и обычно самый маленький. 🟠Оперативная память (ОЗУ) Здесь хранятся данные и программы, с которыми компьютер работает в данный момент. Доступ к ОЗУ быстрый, но оно является временным хранилищем: при выключении устройства данные в ОЗУ теряются. 🟠Постоянная память (ПЗУ, SSD, HDD) Это память для долговременного хранения данных. Она сохраняет информацию даже при выключении питания. HDD (жесткие диски) использовались ранее и работают на принципе магнитного записывания данных, в то время как SSD (твердотельные накопители) работают на основе флеш-памяти и обеспечивают более быстрый доступ к данным. 🟠Виртуальная память Это техника, которая позволяет операционной системе использовать часть жесткого диска (или SSD) как дополнительную оперативную память. Когда ОЗУ заполнено, операционная система может перемещать редко используемые данные из ОЗУ на диск в специальный файл подкачки (swap file), освобождая ОЗУ для других задач. Ставь 👍 и забирай 📚 Базу знаний

🤔 Зачем нужен оператор future? Если речь о Future в Swift Combine — он представляет одноразовое асинхронное событие, которое может завершиться значением или ошибкой. Используется для интеграции старого кода в реактивную модель. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Какие изменения надо сделать в 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() // Обновление произойдет на следующем цикле рендера
Ставь 👍 и забирай 📚 Базу знаний

🤔 Наследником чего является UIWindow? UIWindow наследуется от UIView, а значит, участвует в иерархии отображения. Она представляет основное окно, в котором располагаются все видимые элементы приложения. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое барьеры? Барьер (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");
}
Ставь 👍 и забирай 📚 Базу знаний