Пройдите собеседование с разработчиками iOS, зная ответы на эти важные вопросы

Вот список из 50 вопросов и ответов на собеседование по Swift. Эти вопросы касаются программирования на Swift и разработки приложений для iOS. Вам необходимо знать ответы на эти вопросы, прежде чем вы сможете продемонстрировать свои навыки перед интервьюером.

Эти вопросы не расположены в произвольном порядке - давайте перейдем к делу!

1. Что вызывает ошибку? Как это исправить?

let n1: Int = 1
let n2: Float = 2.0
let n3: Double = 3.34
var result = n1 + n2 + n3

Отвечать:

В Swift неявное приведение типов между двумя типами данных невозможно.

В приведенном выше коде вы пытаетесь сложить вместе три элемента, каждый из которых представляет разные типы данных.

Чтобы исправить это, вам нужно преобразовать каждое значение в один и тот же тип данных. Например:

var result = Double(n1) + Double(n2) + n3

2. Какое значение имеет Len? Почему?

var arr1 = [1, 2, 3]
var arr2 = arr1
arr2.append(4)
var len = arr1.count

Отвечать:

Значение len равно 3, то есть количество элементов в arr1 равно 3. Это потому, что присвоение arr1 arr2 фактически означает, что копия arr1 назначается arr2, поэтому arr1 не изменяется.

В Swift все основные типы данных (логические, целые числа и т. Д.), Перечисления и структуры по своей природе являются типами значений.

Массивы тоже являются типами значений. При перемещении типа значения в Swift вы, по сути, работаете с его копией. Например, при передаче типа значения в качестве аргумента функции создается его копия, поэтому все, что делает функция, не отражается в исходном значении.

3. В чем проблема и как ее исправить?

Рассмотрим этот фрагмент кода, который пытается получить цвет темы из локального хранилища устройства iOS:

var color = UserDefaults.standard.string(forKey: "themeColor")!
print(color)

Сможете ли вы обнаружить ошибку и исправить ее?

Отвечать:

Первая строка извлекает цвет темы из пользовательских значений по умолчанию. Однако этот метод возвращает необязательный (поскольку themeColor может быть не определен). Если ключ не найден, возвращается nil, приведенный выше код дает сбой:

fatal error: unexpectedly found nil while unwrapping an Optional value

Это происходит, когда в первой строке используется ! для принудительного развертывания необязательного элемента, который теперь является nil. Принудительное развертывание следует использовать только в том случае, если вы на 100% уверены, что значение не nil.

Чтобы исправить это, вы можете использовать необязательную привязку, чтобы проверить, найдено ли значение для ключа:

if let color = defaults.stringForKey("themeColor") {
    print(color)
}

4. Какие улучшения вы можете увидеть?

Вы просматриваете пул-реквест и сталкиваетесь с этим методом:

Какие улучшения вы можете предложить автору кода?

Отвечать:

Несмотря на то, что этот код может работать, следует учитывать два момента.

  • Использование жестко запрограммированных строк типа (например ,"West") - плохая идея. Что, если кто-то его пропустит? Чтобы решить эту проблему, следует отказаться от жестко запрограммированных строк и вместо них создать перечисление.
  • Кроме того, как насчет использования оператора switch вместо длинного оператора if-else?

Благодаря этим улучшениям код становится более безопасным и читаемым:

5. Что такое перечисления в Swift?

Отвечать:

Перечисление - это группа связанных значений.

Перечисления позволяют писать типобезопасный код.

enum Direction {
    case North
    case East
    case South
    case West
}

Теперь в вашем коде вы можете вызвать Direction.North, например, вместо использования мистической строки "North" (которая может быть легко написана с ошибками и вызвать досадные ошибки).

6. Что является необязательным в Swift? Как его создать?

Отвечать:

Необязательный - это тип, который может хранить либо значение, либо nil. Вы можете создать необязательное поле, добавив вопросительный знак ? после любого типа:

var number: Int? = 10

7. Что такое typealias в Swift? Как создать его?

Отвечать:

Typealias, как следует из названия, является псевдонимом для существующего типа данных.

Вы можете создать его так:

typealias Weight = Float

Теперь вы можете использовать Weight вместо Float:

let mass1: Weight = 150.0
let mass2: Weight = 220.0
let total: Weight = mass1 + mass2

8. Назовите некоторые преимущества использования Swift

Отвечать:

Назвать несколько:

  • Swift - это типобезопасный язык
  • Имеет поддержку закрытия
  • Имеет дополнительную поддержку типа
  • Имеет встроенную обработку ошибок
  • Имеет поддержку сопоставления с образцом

9. В Swift есть 5 операторов передачи управления - назовите их и объясните, почему они используются.

Отвечать:

Пять заявлений о передаче управления:

  • Break
  • Continue
  • Fallthrough
  • Throw
  • Return

Операторы передачи управления изменяют порядок выполнения вашего кода.

Например, вы можете использовать оператор передачи управления break, чтобы завершить выполнение цикла for, когда это будет сочтено ненужным для продолжения цикла:

for choice in choices:
    if isCorrect(choice):
        print("Correct choice found!")
        break

10. Предложите небольшой рефакторинг этого кода.

if age < 18 {
    driveCar()
} else {
    doNotDrive()
}

Это выражение чистое и хорошо работает, но можете ли вы предложить небольшое улучшение рефакторинга, чтобы сделать его еще лучше?

Отвечать:

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

age < 18 ? driveCar() : doNotDrive()

11. Улучшение читаемости кода.

В нашей компании 20 разработчиков и 20 уникальных стилей кодирования. Как мы можем обеспечить соблюдение некоторых общих стилей / передовых методов кодирования?

Отвечать:

Начните использовать линтер, например Swiftlint. Линтер - это простой в настройке инструмент, который проверяет и исправляет ваши ошибки и применяет передовые методы и соглашения от вашего имени.

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

12. Что такое обработчик завершения в Swift?

Отвечать:

Обработчики завершения - это закрытия в действии.

Предположим, вы выполняете трудоемкую задачу, например сетевой запрос, и хотите что-то сделать сразу после завершения запроса. Но вы определенно не хотите тратить ресурсы, многократно проверяя, продолжается процесс или нет.

Здесь используются обработчики завершения. Обработчик завершения - это закрытие, которое «перезвонит», как только завершится трудоемкий процесс.

13. Как протестировать приложение iOS, если у вас нет физического устройства iOS?

Отвечать:

Если у вас нет устройства iOS, вы можете использовать симуляторы устройств Apple iOS для тестирования своих приложений на Mac.

14. Что делает init () в Swift?

Отвечать:

Метод init() используется для инициализации экземпляра.

Инициализация означает, что вы готовите экземпляр (класса, структуры или перечисления) для использования.

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

15. Объясните разницу между Let и Var в Swift

Отвечать:

В Swift вы можете использовать let для создания константы (значение, которое нельзя изменить) и var для создания переменной (значение, которое можно изменить позже).

16. Что такое PLIST?

Отвечать:

PLIST, или список свойств, представляет собой словарь пар "ключ-значение", которые используются для хранения данных в файловой системе вашего проекта. Например, info.plist.

17. Что такое протоколы в Swift? Приведите пример

Отвечать:

Протокол - это кодовый контракт. Он действует как образец для свойств, методов и т. Д. Он описывает, как должен вести себя тип, соответствующий ему.

Вы не можете создавать экземпляры протоколов. Скорее, вы можете сделать, например, класс соответствует протоколу.

Вот пример протокола, описывающего животное:

Давайте создадим классы Cat и Dog, которые оба соответствуют протоколу Animal. Таким образом, требуется, чтобы они оба реализовали поведение, описанное в протоколе Animal, то есть переменные name, color и метод makeSound():

18. Что такое оператор двойного вопросительного знака?

Отвечать:

Оператор двойного вопросительного знака ?? известен как оператор объединения nil. Он возвращает значение слева, если оно не nil. Если в левой части указано nil, то возвращается значение в правой части.

Nil coalescing можно использовать как сокращение для проверки, является ли необязательное значение nil. Например, вы можете заменить это:

var name: String?
if name != nil {
    print(name)
} else {
    print("N/A")
}

С этим:

print(name ?? "N/A")

19. Что такое охранное заявление? Приведите пример

Отвечать:

Оператор защиты используется для передачи управления программой за пределы области действия. Оператор Guard похож на оператор if, но запускается только при невыполнении некоторых условий.

Например, оператор защиты, используемый для выхода из функции:

func myFun() {
    guard false else {
         print("This block is run")
         return
    }
    print("This is never run")
}
myFun()

Выход:

This block is run

20. Какие три основных типа сбора доступны в Swift?

Отвечать:

  • Массивы: массив - это упорядоченный набор значений.
  • Наборы: набор - это неупорядоченный набор значений.
  • Словари. Словарь - это неупорядоченный набор пар ключ-значение.

21. Что такое Defer в Swift?

Отвечать:

Вы можете использовать метод defer для выполнения кода перед выходом из области видимости. В качестве примера давайте напечатаем что-нибудь прямо перед завершением выполнения функции:

Отсрочка обычно используется при открытии и закрытии контекста в пределах области видимости - например, при доступе к файлам.

22. Можно ли поменять местами две переменные без третьей вспомогательной переменной?

Отвечать:

Да, это возможно. С деструктуризацией кортежа проблему можно решить так:

var a = 1
var b = 2
(a, b) = (b, a)

23. В чем разница между структурами и классами?

Отвечать:

  • Структуры - это типы значений, тогда как классы - это ссылочные типы.
  • Структуры не поддерживают наследование, в отличие от классов.
  • В классе мы можем создать экземпляр с let ключевыми словами и попытаться изменить его свойство, в то время как в структурах нет изменчивости.
  • Структуры не поддерживают приведение типов, но классы поддерживают.

24. Что такое факультативная цепочка?

Отвечать:

Необязательная цепочка означает, что вы можете безопасно вызывать свойство чего-то, что может быть nil.

Необязательная цепочка работает, как следует из названия, путем объединения одного или нескольких дополнительных значений в цепочку с оператором вопросительного знака ?, например:

something?.someValue?.someMethod()

Если nil встречается в любой точке указанной выше цепочки, приложение не вылетает - вместо этого возвращается nil.

25. Что такое необязательная привязка?

Отвечать:

Необязательная привязка проверяет, содержит ли необязательный параметр значение или нет. Если необязательный параметр имеет значение, необязательная привязка делает это значение временно доступным:

В качестве примера следующий код проверяет, является ли имя nil или нет. Если это не так, создается временная константа realName, и ей присваивается значение name.

var name: String? = "Charles"
if let realName = name {
    print (realName)
}

Выход:

Charles

26. Объясните архитектуру MVC

Отвечать:

MVC (Model-View-Controller) - это программная архитектура для разработки приложений для iOS. Это одна из фундаментальных концепций разработки приложений для iOS.

Несколько платформ iOS используют MVC.

Идея MVC - передавать данные из одного места в другое. Это означает, что любой объект попадает в одну из этих трех категорий:

  • Модель. Модель представляет данные приложения. В нем хранится информация, например о товарах в магазине. Модель управляет состоянием приложения.
  • Представление. Представление отвечает за отображение пользовательского интерфейса и взаимодействие с ним. Например, представление отображает таблицу продуктов для пользователя вашего приложения.
  • Контроллер. Контроллер - это то, что склеивает модель и вид. Он отвечает за управление логикой между ними.

27. Что такое параметр входа-выхода в Swift?

Отвечать:

Параметр inout позволяет изменять значение параметра внутри функции.

Чтобы сделать параметр входным-выходным, используйте ключевое слово inout перед типом параметра.

Чтобы передать переменную как вход-выход, используйте & перед ее именем.

Например:

28. Что такое кортеж? Как создать его и как понять из него ценности?

Отвечать:

Кортеж - это значение, которое можно использовать для объединения нескольких значений, например, в пару.

Значения кортежа не обязательно должны быть одного типа.

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

Например:

var coordinates3D = (1.0, 2.0, 5.0)

Чтобы получить доступ к значению внутри кортежа, используйте точечную нотацию и индекс:

let xPos = coordinates3D.0

Также можно создавать кортежи, чтобы у каждого значения было имя:

var coordinates3D = (x: 1.0, y: 2.0, z: 5.0)

В этом случае вы можете получить доступ к определенному значению кортежа по его имени:

let xPos = coordinates3D.x

29. Что такое Swift Messages?

Отвечать:

Swift Messages - это библиотека, используемая для отображения сообщений в виде строки состояния вверху или внизу экрана устройства iOS.

30. Можно ли присвоить параметру функции значение по умолчанию? Как?

Отвечать:

Для параметра можно указать значение по умолчанию:

func eat(food: String = "spaghetti") {
    print("Yum! I ate some good \(food).")
}

31. Что такое дженерики? Приведите пример использования универсальных шаблонов

Отвечать:

Generics позволяет писать гибкий и многократно используемый код, который может работать с любым типом данных.

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

Здесь вы можете использовать дженерики.

Например, вы можете создать общий тип для параметров (для представления любого типа), используя букву, например. T вот так:

32. Что такое недвижимость в фунтах? Что такое геттеры и сеттеры?

Отвечать:

Свойство pounds также известно как вычисляемое свойство.

В Swift вычисленные свойства не сохраняются в объекте. Вычисляемое свойство означает, что его значение вычисляется «по запросу» только при попытке доступа к нему. Вы можете создавать вычисляемые свойства, используя методы get и (необязательно) set.

  • Метод get выполняет вычисление «по запросу», когда вызывается weight.pounds.
  • Метод set обновляет kilograms при обновлении pounds. (Обратите внимание, что set метод является необязательным, и вам не нужен такой метод для создания вычисляемого свойства.)

33. В чем разница между операторами == и ===?

Отвечать:

  • == - оператор равенства.
  • === - оператор идентификации.

Оператор равенства == используется для проверки равенства двух Equatable типов:

"Hello" == "Hello"
10.0 == 5.0 + 5.0

Оператор идентичности === может использоваться для проверки идентичности двух классов, т.е. указывают ли они на один и тот же адрес памяти. Давайте посмотрим на пример:

class Fruit {
    var name = "Banana"
}
let fruit1 = Fruit()
let fruit2 = fruit1 // fruit2 now points to same address as fruit1
fruit1 === fruit2 // true

34. Что такое расширения?

Отвечать:

В Swift вы можете использовать расширения для добавления функциональности к существующему типу.

В Swift вы можете создать расширение, используя ключевое слово extension:

extension SomeExistingType {
    // add new functionality to SomeExistingType here
}

35. Что такое вложенная функция?

Отвечать:

Вложенная функция - это комбинация функции внутри функции:

func outer() {
    func inner() {
       // Do something here
    }
}

36. Как создать базовый класс в Swift?

Отвечать:

Вы можете создать базовый класс, определив класс без суперкласса.

37. Что такое Force Unwrapping? Когда его использовать?

Отвечать:

Принудительное развертывание пытается преобразовать необязательное значение в значение, независимо от того, содержит оно значение или нет.

Принудительное развертывание небезопасно, потому что, если необязательный параметр nil и вы попытаетесь его развернуть, это вызовет ошибку, которая приведет к сбою приложения. Таким образом, этого следует избегать, если вы не на 100% уверены, что необязательный параметр не nil.

38. Перечислите некоторые преимущества использования функций высшего порядка.

Отвечать:

  • Они обеспечивают гибкость.
  • Они полезны в асинхронных вызовах, где нельзя использовать обычные функции.
  • Иногда они улучшают качество кода, делают его короче и лаконичнее.

39. В чем разница между F ileprivate и P rivate ?

Отвечать:

  • Свойство fileprivate можно прочитать в любом месте того же файла Swift, но не за его пределами.
  • Свойство private можно прочитать только внутри того типа, в котором оно было объявлено (а также в расширениях этого типа в том же файле).

40. Как бы вы объяснили, какие функции есть в Swift?

Отвечать:

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

Обычно функции принимают некоторые значения, с которыми они могут работать.

41. В чем разница между N il и N one ?

Отвечать:

Между ними нет разницы:

nil == .none // returns true

Единственная разница в том, что nil используется чаще, чем none.

42. Что такое словарь в Swift?

Отвечать:

Словарь - это базовый тип коллекции в Swift. Его можно использовать для хранения пар ключ-значение.

Вы можете легко получить доступ к значению, зная ключ:

let dict = ["a": 1, "b": 2]
let valueOfA = dict["a"]

43. Для чего используется ключевое слово Mutating?

Отвечать:

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

Например:

По умолчанию это невозможно для типов значений (структур и перечислений), но возможно для ссылочных типов (классов).

44. Можете ли вы исправить проблему в этом коде?

Этот код ниже вызывает ошибку компилятора. Что случилось? Как это исправить?

Отвечать:

Блок else оператора guard требует пути выхода.

Вы можете, например, использовать return, чтобы предоставить ему один:

45. Что такое деинициализатор? Как его создать?

Отвечать:

Деинициализатор запускается до освобождения экземпляра класса.

Вы можете создать деинициализатор, используя ключевое слово deinit.

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

Вот пример деинициализатора, который устанавливает number обратно в 0, когда экземпляр Example освобождается.

var number = 15
class Example {
    init() {
       number *= 10
    }
    
    deinit {
        number = 0
    }
}

46. ​​В чем разница между функциями и методами?

Отвечать:

Есть небольшая разница между функцией и методом. Оба являются многократно используемыми фрагментами кода, однако методы принадлежат классам, структурам или перечислениям, а функции - нет.

47. Как запретить классу наследоваться?

Отвечать:

Сделав класс последним с помощью ключевого слова final. Например:

final class Animal {
    let name = "I'm a furry animal"
}

48. Что такое ленивые переменные? Когда лучше использовать?

Отвечать:

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

Например:

lazy var tallest: Person? = {
    return people.max(by: { $0.height < $1.height })
}()

49. Что такое автозащита в Swift? Как и когда вы должны его использовать?

Отвечать:

Автозамкнутость оборачивает аргумент функции в замыкание. Когда вызывается автоматическое закрытие, оно возвращает значение выражения, заключенного внутрь.

Иногда синтаксически удобно использовать автоматическое закрытие при работе с функцией, которая принимает аргумент замыкания. Это связано с тем, что автоматическое закрытие позволяет не использовать фигурные скобки {}. Это может сделать код более читабельным.

Однако имейте в виду, что Apple говорит об использовании автозамков:

Обычно вызываются функции, которые принимают автоматическое закрытие, но нечасто реализовывать такую ​​функцию.

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

50. Чего не хватает в этом фрагменте кода?

enum Example {
  case something(Int, Example)
}

Отвечать:

В Swift можно создавать рекурсивные перечисления, подобные приведенным выше. Ниже приведен абстрактный пример - однако использование рекурсивных перечислений по умолчанию отключено, вам необходимо включить его с помощью ключевого слова indirect:

enum Example {
  indirect case something(Int, Example)
}

Заключение

Спасибо за прочтение. Я надеюсь, что они вам пригодятся и помогут вам найти работу своей мечты!

Я хотел бы присоединиться к вашей сети LinkedIn. Не стесняйтесь подключать Artturi Jalli.

Ресурсы