5 рандомных вопросов на собеседовании iOS разработчика

в 17:16, , рубрики: interview, iOS, swift

Всем привет!

Рассмотрим 5 вопросов, которые вам могут задать на собеседовании на позицию iOS разработчика. Скорее всего, это вопросы уровня Junior, но т.к. сейчас непонятно кто, что и у кого спрашивает, поэтому не будем разводить холивар :)

Вопрос №1: Можно ли создать необязательные методы в протоколах?

Ответ: Существует два способа создания необязательных методов для протоколов.

  1. Использование ключевого слова optional.

@objc protocol NameProtocol {
    @objc optional func nameMethod()
}

class NameClass: NameProtocol {
}

Плюсы:
- Не нужно указывать реализацию по умолчанию

Минусы:
- Использование ключевого слова optional доступно только для @objc protocol. Это означает, что протоколу могут соответствовать только классы, унаследованные от NSObject. Структуры и перечисления не могут соответствовать протоколу.
- Перед вызовом необходимо проверять реализован ли данный метод.

  1. Реализация по умолчанию

protocol NameProtocol {
    var nameProperty: String { get set }
}

extension NameProtocol {
    func nameMethod() {
        print("default implementation")
    }
}

class NameClass: NameProtocol {
    var nameProperty: String = "name"
}

Плюсы:
- Протоколу могут соответствовать классы, структуры, перечисления.
- Возможность использования Generics.
- Уверенность в том, что существует или собственная реализация метода или реализация по умолчанию.

Минусы:
- Не всегда существует возможность написать универсальную реализация по умолчанию.
- Невозможно отличить реализацию по умолчанию от ее отсутствия.

Вопрос №2: Чем static отличается от class?

Ответ: static и class достаточно похожи, но существуют различия.

Сходство:
- static и class делают свойство/метод, к которому они были применены, свойством/методом типа. Вызывать такое свойство/метод можно напрямую, без создания экземпляра.

class Car {
    static let wheels = 4
}
Car.wheels

Различие:
- class может применяться только к вычисляемым свойствам
- class может применяться только к свойства и методам класса
- class позволяет переопределять свойство/метод

class Car {
    class var wheels: Int {
        4
    }
}

class Mercedes: Car {
    override class var wheels: Int {
        3
    }
}

Вопрос №3: Могут ли ленивые вычисляемые свойства вычисляться больше одного раза?

Ответ: Нет

lazy var - переменная, которая инициализируется только при первом доступе.
Код инициализации выполняется только один раз. Результат сохраняется в переменной.
При последующем обращении будет возвращено сохраненное значение.

class NameClass {
    lazy var lazyProperty: Int = {
        print("lazyProperty")
        return 0
    }()
}

let instance = NameClass()
instance.lazyProperty
instance.lazyProperty
instance.lazyProperty

//Консоль
//lazyProperty

Сообщение "lazyProperty" выведется в консоль только один раз, при инициализации lazyProperty. При последующих обращениях возвращается сохраненное значение.

Более интересный пример:

class NameClass {
    var a: Int
    var b: Int
  
    lazy var lazyProperty: Int = {
        a + b
    }()
  
    init(a: Int, b: Int) {
        self.a = a
        self.b = b
    }
}

let instance = NameClass(a: 10, b: 2)
instance.lazyProperty
instance.a = 20
instance.b = 15
print(instance.lazyProperty)

//Консоль
//12

В консоль выведется значение 12, рассчитанное и сохраненное при первом обращении.

Вопрос №4: Почему нельзя вызвать memberwise initializer, если он содержит хотя бы одно свойство с уровнем private?

Ответ: При запуске кода, расположенного ниже, возникнет ошибка.

struct NameStruct {
    private let first: Int
}

let nameStruct = NameStruct(first: 1)

В описании ошибки говориться о том, что данный инициализатор имеет уровень доступа private, поэтому вызов невозможен.

Такое поведение связано с тем, что memberwise инициализатор устанавливает значения напрямую. Т.к. свойство имеет уровень доступа private, становится невозможным установить значение из вне. Инициализатору присваивается уровень доступа private.

Вопрос №5: Почему классы не обладают memberwise инициализатором как структуры?

Ответ: При ответе на данный вопрос, предлагаю сослаться на доводы Криса Латтнера.

  1. При реализации собственного инициализатора memberwise инициализатор пропадает. Нет простого способа вернуть его.

Пример со структурой:

struct NameStruct {
    let first: String
    let second: String

    init(first: String) {
        self.first = first
        self.second = "two"
    }
}

let nameStruct = NameStruct(first: "1", second: "2") //error
  1. Контроль доступа. Для свойств с уровнем доступа private memberwise инициализатор требует установить значение по умолчанию. Если же хотя бы один из членов инициализатора имеет уровень доступа private, инициализатор также будет иметь уровень доступа private и недоступен для использования. (Вопрос №4)

  2. memberwise инициализатор должен уметь устанавливать значение по умолчанию для переменных.

  3. memberwise инициализатор захватывает ленивые свойства (lazy var)

Автор: yaSkazalGorbatiy

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js