Перед вами список из 50 вопросов и ответов для собеседования по Swift. Эти вопросы посвящены программированию на Swift и разработке приложений для iOS. Вы должны знать ответы на них, прежде чем у вас появится шанс продемонстрировать свои навыки перед интервьюером. Кроме того, не стесняйтесь использовать эти вопросы для собеседования по Swift для тренировки перед экзаменом. Эти вопросы для собеседования расположены в случайном порядке, а не от простого к сложному. Ещё больше интересных статей (и интересных фактов) можно прочесть в канале об iOS-разработке. В Swift неявное приведение типов между двумя типами данных невозможно. В приведенном выше коде вы пытаетесь сложить вместе три элемента, каждый из которых представляет собой другой тип данных. Чтобы исправить это, необходимо преобразовать каждое значение к одному типу данных. Например:  Значение len равно 3, т.е. количество элементов в arr1 равно 3. Это происходит потому, что присвоение arr1 к arr2 фактически означает, что копия arr1 присваивается к arr2, поэтому arr1 не затрагивается. В Swift все основные типы данных (булевы, целые числа и т. д.), перечисления и структуры по своей природе являются типами значений. Массивы тоже являются типами значений. Перемещая тип значения в Swift, вы, по сути, работаете с его копией. Например, при передаче типа значения в качестве аргумента функции создается его копия, поэтому все, что делает функция, не отражается на исходном значении. Рассмотрим этот фрагмент кода, который пытается получить цвет темы из локального хранилища устройства iOS: Смогли ли вы заметить ошибку и исправить ее? Первая строка извлекает цвет темы из user defaults. Этот метод, однако, возвращает optional (поскольку themeColor может быть не определен). Если ключ не найден, возвращается nil, что приводит к крашу: Это происходит потому, что в первой строке используется ! для force unwrap optional, которое теперь  nil. Force unwrapping должно использоваться только тогда, когда вы на 100% уверены, что значение не  nil. Чтобы исправить это, вы можете использовать optional binding для проверки, найдено ли значение для ключа:  Вы просматриваете пулл-реквест и столкнулись с этим методом: Какие улучшения вы можете предложить автору кода? Даже если этот код может работать, есть два момента, которые следует учитывать. Использование жестко закодированных строк типа (например, "West") - плохая идея. Что если кто-то неправильно напишет это слово? Чтобы решить эту проблему, следует отказаться от жестко закодированных строк и вместо них использовать перечисление. Кроме того, как насчет использования оператора switch вместо длинного оператора if-else? Благодаря этим улучшениям код станет более безопасным и читабельным:  Перечисление (enumeration)- это группа связанных значений. Перечисления позволяют писать безопасный для типов код. Теперь в своем коде вы можете вызвать, например, Direction.North, вместо того чтобы использовать мистическую строку "North" (которая легко может быть неправильно написана и вызвать раздражающие ошибки). Больше информации о перечислениях можно прочесть в этой статье. Optional - это тип, который может хранить либо значение, либо nil. Вы можете создать optional, добавив вопросительный знак ? после любого типа: Typealias, как следует из названия, является псевдонимом для существующего типа данных. Вы можете создать его следующим образом: Теперь вы можете использовать Weight вместо Float: Вот лишь некоторые из них: Swift - язык с типобезопасностью В нем есть поддержка замыканий Поддерживаются опциональные типы Встроенная обработка ошибок Поддерживается сопоставление шаблонов Вот они слева-направо (сверху-вниз): Break Continue Fallthrough Throw Return Операторы передачи управления изменяют порядок выполнения вашего кода. Например, вы можете использовать оператор передачи управления break для завершения выполнения цикла for, когда продолжение цикла считается ненужным: Этот код хорошо работает - но можете ли вы предложить небольшое улучшение рефакторинга, чтобы сделать его еще лучше? Вы можете использовать тернарный условный оператор для преобразования этого выражения в однострочное, что в данном случае не ухудшает читабельность, а улучшает ее.  В нашей компании 20 разработчиков и 20 уникальных стилей кодирования. Как мы можем внедрить некоторые общие стили кодирования/лучшие практики? Можно использовать линтер, например, Swiftlint. Линтер - это простой в настройке инструмент, который проверяет и исправляет ваши ошибки и внедряет лучшие практики и соглашения от вашего имени. Вы можете использовать рекомендации по умолчанию, но также можете настроить его в соответствии с предпочтениями вашей компании.  Completion handlers (обработчики завершения) — это замыкания в действии. Предположим, вы выполняете трудоемкую задачу, например сетевой запрос, и хотите что-то сделать сразу после завершения запроса.  Но вы определенно не хотите тратить ресурсы впустую, проверяя несколько раз, продолжается ли процесс или нет. Здесь используются обработчики завершения. Обработчик завершения — это замыкание, которое «вернется» сразу после завершения трудоемкого процесса. Узнайте больше о замыканиях и о том, как передать функцию в качестве параметра. Если у вас нет устройства iOS, вы можете использовать симуляторы устройств iOS от Apple для тестирования своих приложений на Mac. Метод init() используется для инициализации экземпляра. Инициализация означает подготовку экземпляра (класса, структуры или перечисления) к использованию. В процессе инициализации вы устанавливаете начальные значения для каждого свойства экземпляра. Вы также можете выполнить некоторые другие подготовительные действия, прежде чем экземпляр будет готов к использованию. В Swift вы можете использовать let для создания константы (значения, которое нельзя изменить) и var для создания переменной (значения, которое может быть изменено позже). Некоторые дополнительные подробности вы можете найти в этой статье. Plist, или список свойств, - это словарь пар ключ-значение, которые используются для хранения данных в файловой системе вашего проекта. Например, info.plist. Протокол действует как чертеж для свойств, методов и т.д. Он описывает, как должен вести себя тип, соответствующий ему. Вы не можете создавать экземпляры протоколов. Скорее, вы можете сделать так, чтобы, например, класс соответствовал протоколу. Вот пример протокола, описывающего животное: Давайте создадим классы Cat и Dog, которые оба соответствуют протоколу Animal. Таким образом, требуется, чтобы они оба реализовывали поведение, описанное в протоколе Animal - то есть переменные name, color и метод makeSound(): Оператор двойного вопросительного знака ?? известен как оператор объединения (слияния) nil. Он возвращает значение в левой части, если оно не равно nil. Если левая часть равна nil, то возвращается значение в правой части. Его можно использовать как сокращение для проверки того, является ли опциональное значение nil. Например, вы можете заменить это: На это: Оператор guard используется для передачи управления программой за пределы области видимости. Оператор guard похож на оператор if, но он запускается только тогда, когда некоторые условия не выполняются. Например, оператор guard используется для выхода из функции: Вывод: Узнайте больше о ключевом слове guard, прочитав эту статью. Массивы: Массив - это упорядоченная коллекция значений. Наборы: Набор - это неупорядоченная коллекция значений. Словари: Словарь - это неупорядоченная коллекция пар ключ-значение. Вы можете использовать метод defer для выполнения кода перед выходом из области видимости. В качестве примера, давайте напечатаем что-нибудь прямо перед завершением выполнения функции: Defer обычно используется при открытии и закрытии контекста внутри области видимости - например, при доступе к файлам. Это классический вопрос на собеседовании Swift. Да, это возможно. С помощью  tuple destructuring вы можете решить проблему следующим образом: Структуры - это типы значений, в то время как классы - ссылочные типы. Структуры не поддерживают наследование, а классы поддерживают. В классе мы можем создать экземпляр с помощью ключевых слов let и попытаться изменить его свойство, в то время как в структурах такой возможности нет. Структуры не поддерживают приведение типов, а классы поддерживают. Необязательная цепочка означает, что вы можете безопасно вызвать свойство чего-то, что может быть nil. Optional chaining работает, как следует из названия, путем объединения одного или нескольких необязательных значений с помощью оператора со знаком вопроса ?, например, так: Если nil встречается в любой точке вышеприведенной цепочки, приложение не крашится - вместо этого возвращается nil. Опциональное связывание проверяет, содержит ли опция значение или нет. Если опция имеет значение, опциональное связывание делает это значение временно доступным: Например, следующий код проверяет, является ли имя nil или нет. Если нет, то создается временная константа realName и ей присваивается значение name. Вывод: MVC (Model-View-Controller) - это программная архитектура для разработки приложений для iOS. Это одна из фундаментальных концепций разработки приложений для iOS. Множество iOS-фреймворков используют MVC. Идея MVC заключается в передаче данных из одного места в другое. Это означает, что любой объект попадает в одну из этих трех категорий: Model: Модель представляет данные приложения. Она хранит информацию, например, товары в магазине. Модель управляет состоянием приложения. View: Вью отвечает за отображение и взаимодействие с пользовательским интерфейсом. Например, вью отображает таблицу товаров для пользователя вашего приложения. Controller: Контроллер - это то, что склеивает модель и представление. Он отвечает за управление логикой, которая происходит между ними. Параметр inout позволяет изменять значение параметра внутри функции. Чтобы сделать параметр in-out, используйте ключевое слово inout перед типом параметра. Чтобы передать переменную в качестве in-out, используйте & перед ее именем. Например: Здесь можно прочитать подробнее о параметрах inout. Tuple (кортеж) - это значение, которое можно использовать для объединения нескольких значений вместе, например, в виде пары. Значения tuple не обязательно должны быть одного типа. Вы можете создать tuple, разделив значения запятыми внутри круглых скобок. Например: Чтобы получить доступ к значению внутри tuple, используйте точечную нотацию и индекс: Кортежи также могут быть созданы таким образом, чтобы каждое значение имело имя: В этом случае вы можете получить доступ к определенному значению кортежа по его имени: Swift Messages - это библиотека, используемая для отображения сообщений в виде строки состояния в верхней или нижней части экрана устройства iOS. Можно задать значение по умолчанию для параметра: Дженерики позволяют писать гибкий и многократно используемый код, который может работать с любым типом данных. Представьте, что вы пишете трехмерную векторную структуру, но хотите иметь возможность создавать векторы, используя целые, плавающие и двойные числа. Вы определенно не хотите писать один и тот же код для каждого типа данных отдельно. Именно здесь вы можете использовать дженерики. Например, вы можете создать общий тип для параметров (для представления любого типа), используя букву, например T, следующим образом: Свойство pounds также известно как вычисляемое свойство. В Swift вычисляемые свойства не хранятся в объекте. Вычисляемое свойство означает, что его значение вычисляется "по требованию" только при попытке доступа к нему. Вы можете создавать вычисляемые свойства с помощью методов get и (необязательно) set. Метод get выполняет вычисление "по требованию", когда вызывается weight.pounds. Метод set обновляет килограммы, когда обновляются фунты. (Обратите внимание, что метод set является необязательным, и вам не нужен такой метод для создания вычисляемого свойства).  == - оператор равенства. === - оператор тождества. Оператор равенства == используется для проверки равенства двух типов Equatable: Оператор тождества === может быть использован для проверки идентичности двух классов, т.е. указывают ли они на один и тот же адрес памяти. Рассмотрим пример: Узнайте больше о разнице между == и === здесь. В Swift вы можете использовать расширения для добавления функциональности к существующему типу. В Swift вы можете создать расширение с помощью ключевого слова extension: Вложенная функция - это комбинация функции внутри функции: Вы можете создать базовый класс, просто определив класс без суперкласса. Force Unwrapping (принудительное разворачивание) пытается преобразовать опциональное значение в значение независимо от того, содержит оно значение или нет. Принудительное разворачивание небезопасно, потому что если опция nil и вы попытаетесь ее развернуть, это вызовет ошибку, которая приведет к краху приложения. Таким образом, ее следует избегать, если вы не уверены на 100%, что опция не является nil. Они обеспечивают гибкость. Они полезны в асинхронных вызовах, где обычные функции не могут быть использованы. Иногда они улучшают качество кода и делают его короче и лаконичнее. Свойство fileprivate может быть прочитано в любом месте того же файла Swift, но не за его пределами. Свойство private можно прочитать только внутри типа, в котором оно было объявлено (а также в расширениях этого типа в том же файле). Подробнее о private и fileprivate здесь. Функция позволяет определять многократно используемые блоки кода. Функция может выполнять задачу, которая является частью вашей программы. Обычно функции принимают некоторые значения, с которыми они могут работать. Между ними нет разницы: Пожалуй, единственное "отличие" заключается в том, что использование nil встречается чаще, чем использование none. Словарь - это основной тип коллекции в Swift. Он может использоваться для хранения пар ключ-значение. Вы можете легко получить доступ к значению, зная ключ: Вы можете использовать ключевое слово mutating, чтобы разрешить изменение свойств структуры в методе, пометив этот конкретный метод mutating. Например: По умолчанию это невозможно для типов значений (структур и перечислений), но возможно для ссылочных типов (классов). Приведенный ниже код выдает ошибку компилятора. Что не так? Как вы можете это исправить? Блок else оператора guard требует выходной путь. Вы можете, например, использовать return, чтобы предоставить ему такой вариант:  Деинициализатор запускается до того, как экземпляр класса будет деаллоцирован. Вы можете создать деинициализатор, используя ключевое слово deinit. Этот метод полезен только в том случае, если вам нужно сделать некоторую уборку перед деаллокацией экземпляра класса. В большинстве случаев достаточно позволить Swift сделать это автоматически от вашего имени. Вот пример деинициализатора, который устанавливает number обратно в 0 при деаллокации экземпляра Example. Между функцией и методом есть небольшая разница. Оба являются многократно используемыми фрагментами кода, однако методы принадлежат классам, структурам или перечислениям, а функции - нет. Сделать класс конечным, используя ключевое слово final. Например: Подробнее о преимуществах final можно прочитать здесь. Начальное значение ленивой переменной вычисляется при первом обращении к ней. Ленивые переменные можно использовать для оптимизации кода, не выполняя ненужную работу раньше времени. Например: Чтобы узнать больше о lazy, ознакомьтесь с этой статьей. Автозамыкание оборачивает аргумент функции в замыкание. Когда вызывается autoclosure, оно возвращает значение выражения, завернутого внутрь. Автозамыкание - это не что иное, как синтаксическое удобство для написания более чистого кода. Иногда синтаксически удобно использовать autoclosure при работе с функцией, которая принимает аргумент замыкания. Это происходит потому, что autoclosure позволяет не использовать фигурные скобки {}. Это может сделать код более читабельным. Однако помните, что Apple говорит об использовании автозамыканий : Обычно принято вызывать функции, которые принимают autoclosure, но не принято реализовывать такого рода функции. Вот пример того, как autoclosure упрощает код. В первом фрагменте используется обычное замыкание, а во втором - autoclosure. Посмотрите, как вызов функции I_will стал более читабельным во втором фрагменте: Как видите, вызов функции I_will больше не требует использования фигурных скобок. В Swift можно создавать рекурсивные перечисления, подобные приведенным выше. Ниже приведен абстрактный пример - однако использование рекурсивных перечислений по умолчанию отключено, вам необходимо включить его с помощью ключевого слова indirect:  Это большое количество вопросов для собеседования по Swift. Спасибо, что прочитали. Надеюсь, вы найдете их полезными, и они помогут вам найти работу вашей мечты! - дополнение к статье от пользователя  XanKraegor.Если вам понравилась статья, то подписывайтесь, тут я делюсь историями о разработке.  Мобильный разработчик