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

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

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

Начать курс

Введение

Собеседование на позицию iOS/macOS разработчика — это не только проверка знания фреймворков UIKit или SwiftUI. В первую очередь работодатель оценивает ваше понимание языка Swift: его синтаксиса, особенностей управления памятью, работы с многопоточностью и типовой системы. Даже если вы уверенно пишете приложения, без теоретической базы легко провалить техническое интервью.

В этой статье мы собрали топ вопросов, которые чаще всего задают на собеседованиях по Swift в 2025 году. Каждый вопрос сопровождается подробным объяснением и примером кода. Материал будет полезен как джуниорам, так и разработчикам с опытом, желающим освежить знания.

1. Опциональные типы (Optionals) и безопасность

Почему Swift использует Optionals?

Swift — язык с строгой типизацией, и опциональные типы — его ключевая фича для безопасной работы с nil. В отличие от Objective-C, где nil — это просто нулевой указатель, в Swift Optional — это перечисление (enum) с двумя случаями: none (nil) и some(Wrapped). Это заставляет разработчика явно обрабатывать отсутствие значения, предотвращая краши.

Как извлечь значение из Optional?

Есть несколько способов:

  • Force unwrapping — оператор !. Используется только когда вы точно уверены, что значение не nil.
  • Optional binding — конструкция if let или guard let.
  • Nil-coalescing operator — ?? для задания значения по умолчанию.
var name: String? = "Alice"

// Force unwrapping (опасно!)
print(name!)

// Optional binding
if let unwrappedName = name {
    print("Hello, \(unwrappedName)")
}

// Nil-coalescing
let displayName = name ?? "Guest"
print(displayName)

Что такое Implicitly Unwrapped Optionals (IUO)?

Это опциональный тип, который автоматически извлекается при обращении. Объявляется с помощью ! после типа. Используется в основном для свойств, которые инициализируются после init (например, IBOutlet в UIKit). Однако в современном Swift (5.x) IUO ведут себя как обычные Optionals, и компилятор предупреждает о рисках.

2. Управление памятью: ARC и циклы сильных ссылок

Как работает ARC в Swift?

Automatic Reference Counting (ARC) — это механизм подсчета ссылок. Каждый экземпляр класса имеет счетчик ссылок. Когда счетчик падает до нуля, объект удаляется из памяти. ARC работает только с reference types (классы, замыкания). Value types (структуры, перечисления) хранятся в стеке и управляются копированием.

Что такое цикл сильных ссылок (retain cycle)?

Цикл возникает, когда два объекта ссылаются друг на друга через сильные ссылки, и ARC не может их освободить. Это приводит к утечке памяти. Решение — использовать слабые (weak) или бесхозные (unowned) ссылки.

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, а когда unowned?

  • weak — всегда optional, автоматически становится nil при освобождении объекта. Используется, когда время жизни ссылки может быть короче, чем у владельца.
  • unowned — non-optional, предполагает, что объект будет жить столько же или дольше. Опасен: если объект освобожден, обращение к unowned вызовет crash.

3. Замыкания (Closures) и захват значений

Чем замыкания отличаются от функций?

Замыкания — это анонимные функции, которые могут захватывать и хранить ссылки на переменные из окружающего контекста. В Swift функции — это частный случай замыканий (имеют имя). Замыкания бывают трех видов: глобальные функции (с именем, не захватывают), вложенные функции (захватывают из внешней функции) и выражения-замыкания (анонимные).

Что такое @escaping closure?

По умолчанию замыкание является non-escaping — оно выполняется внутри тела функции и не сохраняется за её пределами. Если замыкание может быть вызвано после возврата функции (например, сохранено в свойство или передано в асинхронный колбэк), его нужно пометить как @escaping. Это ключевое слово напоминает разработчику о возможном retain cycle.

class NetworkManager {
    var completionHandler: (() -> Void)?

    func fetchData(completion: @escaping () -> Void) {
        // Сохраняем замыкание для асинхронного вызова
        self.completionHandler = completion
        DispatchQueue.global().async {
            // ... работа ...
            DispatchQueue.main.async {
                completion()
            }
        }
    }
    
    deinit {
        print("NetworkManager deallocated")
    }
}

Как избежать retain cycle в замыканиях?

Если замыкание захватывает self и сохраняется в свойстве объекта, возникает цикл. Решение — использовать [weak self] или [unowned self] в списке захвата.

class ViewController: UIViewController {
    var onButtonTap: (() -> Void)?
    
    func setupHandler() {
        // [weak self] — обязателен, чтобы избежать цикла
        onButtonTap = { [weak self] in
            guard let self = self else { return }
            self.view.backgroundColor = .red
        }
    }
}

4. Многопоточность: GCD и async/await

В чем разница между serial и concurrent queue?

  • Serial queue — выполняет задачи последовательно, одну за другой. Гарантирует порядок выполнения.
  • Concurrent queue — запускает несколько задач одновременно (на разных потоках). Порядок не гарантирован.

GCD (Grand Central Dispatch

Блоги

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