Как пройти собеседование по Swift: топ вопросов от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Почему Swift — ключ к успешному собеседованию

Собеседование по Swift — это не просто проверка синтаксиса. Apple-экосистема требует понимания фундаментальных принципов языка, управления памятью и современных фреймворков. В этой статье мы разберем топ вопросов, которые вам обязательно зададут на любом уровне — от Junior до Senior. Вы узнаете не только правильные ответы, но и типичные ловушки, в которые попадают кандидаты.

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

1. Основы Swift: Optional, Value vs Reference Types

Что такое Optional и зачем он нужен?

Optional — это перечисление (enum), которое может быть либо .none (nil), либо .some(Wrapped). Это способ Swift безопасно работать с отсутствием значения.

var name: String? = "Alice"
var age: Int? = nil

// Безопасное извлечение
if let unwrappedName = name {
    print("Hello, \(unwrappedName)")
} else {
    print("Name is nil")
}

Типичная ошибка: Использование force unwrap (!) без проверки. Всегда предпочитайте guard let или if let.

Value Types vs Reference Types

Swift строго разделяет типы:

  • Value Types (структуры, перечисления, базовые типы) — копируются при присваивании.
  • Reference Types (классы) — передаются по ссылке.
struct Point {
    var x: Int
    var y: Int
}

class Car {
    var model: String
    init(model: String) { self.model = model }
}

var point1 = Point(x: 1, y: 2)
var point2 = point1
point2.x = 5 // point1.x останется 1

var car1 = Car(model: "Tesla")
var car2 = car1
car2.model = "BMW" // car1.model тоже станет "BMW"

Вопрос на собеседовании: "Почему Apple рекомендует использовать структуры вместо классов?" Ответ: безопасность потоков, предсказуемость, отсутствие ARC-оверхеда.

2. Memory Management и ARC: Как избежать утечек

Как работает Automatic Reference Counting (ARC)?

ARC автоматически подсчитывает ссылки на объекты классов. Когда счетчик достигает нуля, память освобождается. Проблемы возникают при циклических ссылках.

class Person {
    let name: String
    var apartment: Apartment?
    init(name: String) { self.name = name }
    deinit { print("\(name) deallocated") }
}

class Apartment {
    let unit: String
    weak var tenant: Person?  // weak — слабая ссылка
    init(unit: String) { self.unit = unit }
    deinit { print("Apartment \(unit) deallocated") }
}

var john: Person? = Person(name: "John")
var unit4A: Apartment? = Apartment(unit: "4A")
john?.apartment = unit4A
unit4A?.tenant = john
john = nil
unit4A = nil
// Оба объекта будут освобождены

Ключевые модификаторы:

  • weak — всегда optional, автоматически становится nil при освобождении.
  • unowned — не optional, предполагает, что объект жив (риск crash).

Типичный вопрос: "В чем разница между weak и unowned?" Ответ: weak безопаснее, unowned удобнее для обязательных зависимостей (например, делегат).

3. Фреймворки: UIKit vs SwiftUI, GCD и Protocols

UIKit: Жизненный цикл ViewController и Delegate Pattern

Понимание viewDidLoad, viewWillAppear, viewDidDisappear — база. Но на собеседовании часто спрашивают про Delegate pattern:

protocol MyDelegate: AnyObject {
    func didTapButton()
}

class MyView: UIView {
    weak var delegate: MyDelegate?
    
    @objc func buttonTapped() {
        delegate?.didTapButton()
    }
}

class MyViewController: UIViewController, MyDelegate {
    let myView = MyView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        myView.delegate = self
    }
    
    func didTapButton() {
        print("Button was tapped!")
    }
}

Важно: Делегат должен быть AnyObject (только классы) и объявлен как weak.

SwiftUI: @State, @Binding и реактивное программирование

SwiftUI меняет парадигму. Основные property wrappers:

  • @State — для локального состояния внутри view.
  • @Binding — для передачи состояния дочерним view.
  • @ObservedObject / @StateObject — для внешних моделей.
struct CounterView: View {
    @State private var count = 0
    
    var body: some View {
        VStack {
            Text("Count: \(count)")
            Button("Increment") {
                count += 1
            }
        }
    }
}

Вопрос: "Когда использовать @StateObject, а когда @ObservedObject?" Ответ: @StateObject — когда view создает объект, @ObservedObject — когда получает его извне.

Grand Central Dispatch (GCD) и Concurrency

Понимание очередей — must-have:

DispatchQueue.global(qos: .background).async {
    // Тяжелая работа в фоне
    let result = performHeavyTask()
    
    DispatchQueue.main.async {
        // Обновление UI
        self.label.text = result
    }
}

Новые подходы: async/await (Swift 5.5+) — более читаемый код:

func fetchData() async throws -> Data {
    let url = URL(string: "https://api.example.com")!
    let (data, _) = try await URLSession.shared.data(from: url)
    return data
}

Типичная ошибка: Забыть переключиться на main queue для UI-обновлений.

4. Продвинутые темы: Generics, Protocols с Associated Types, Result Builders

Generics и Protocol-Oriented Programming

Swift — язык с протокол-ориентированным программированием. Умение писать generic-код — признак Senior-уровня:

func swapTwoValues<T>(_ a: inout T, _ b: inout T) {                

Блоги

Рекомендаций по книгам