Собеседование iOS-разработчика: устные вопросы по языку Swift

1
2123

Перейдем к более открытому варианту тестирования – собеседование iOS-разработчика с устными вопросами по Swift. Вместе с ними также приведены ответы.

Собеседование iOS

Предыдущая статья: Язык Swift: вопросы и ответы на собеседовании

Собеседование iOS: устные вопросы

Начальный уровень

Вопрос №1 – Swift 1.0 и далее

Что такое опционал и какие проблемы он призван решать?

Решение внутри

Опционал считается мощным инструментом языка Свифт. Если после объявления типа поставить вопросительный знак, это будет указывать на то, что значение либо есть, либо его нет, а String и String? – это два разных типа. Например, в Objective-C отсутствие значения доступно только в ссылочных типах, и используется специальное значение nil.

Swift с его опционалами расширяет концепцию отсутствия значения как для ссылочных, так и для других типов. Данная переменная может содержать или какое-то значение, или nil. Чтобы узнать, что «внутри», достаточно развернуть опционал.

[свернуть]

Вопрос №2 – Swift 1.0 и далее

Когда вы должны использовать структуру, а когда – класс?

Решение внутри

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

В Swift классы и структуры отличаются рядом особенностей. Выведем обобщенную разницу следующим образом:

  1. Классы поддерживают наследование, структуры – нет.
  2. Классы являются ссылочными типами, структуры – это типы значений.

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

Подробную информацию можно найти здесь.

[свернуть]

Вопрос №3 – Swift 1.0 и далее

Что такое дженерики и какие проблемы они решают?

Решение внутри

Дженерики используются, чтобы алгоритмы безопасно работали с типами. В Swift дженерики могут юзаться как в функциях, так и в типах данных: например, в классах, структурах, etc.

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

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

Знающий Objective-C может подумать о решении с помощью NSObject:

Этот код работает, но есть одно «но»: он позволяет сравнивать строку с целым числом. Например:

Приложение не крашится, но сравнение строки с целым числом, вероятно, не должно допускаться. С дженериками вы можете объединить две функции в одну и сохранить безопасность типов:

Этот код достигает намеченного результата и предотвращает передачу параметров другого типа.

Собеседование iOS

[свернуть]

Вопрос №4 – Swift 1.0 и далее

Объясните суть неявно развернутых (извлеченных) опционалов.

Решение внутри

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

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

[свернуть]

Вопрос №5 – Swift 1.0 и далее

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

Подсказка: Есть по крайней мере семь способов.

Решение внутри

  • оператор принудительного извлечения ! – небезопасный;
  • неявное извлечение – во многих случаях небезопасно;
  • опциональное связывание – безопасное;
  • опциональная цепочка  – безопасна;
  • оператор объединения со значением nil – безопасный;
  • Swift 2.0 оператор guard – безопасный;
  • Swift 2.0 паттерн опционала – безопасный.
[свернуть]

Swift

Средний уровень

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

Вопрос №1 – Swift 1.0 и далее

Swift – это язык ООП или функциональный язык программирования?

Решение внутри

Swift – гибридный язык, который поддерживает оба типа. Он реализует три основных принципа ООП:

  • Инкапсуляция
  • Наследование
  • Полиморфизм

Что же касается Swift как функционального языка, то существуют разные, но эквивалентные способы его определения.

Один из наиболее распространенных в Википедии: «… парадигма программирования, которая рассматривает вычисления как оценку математических функций, избегает изменяющихся состояний и изменяемых данных».

Нельзя утверждать, что Swift – полноценный функциональный язык, но основы присутствуют.

[свернуть]

Вопрос №2 – Swift 1.0 и далее

Что из этого включено в Swift?

  • Generic-классы
  • Generic-структуры
  • Generic-протоколы
Решение внутри

1 и 2 включены. Дженерики могут использоваться в классах, структурах, перечислениях, глобальных функциях и методах.

3 частично реализуется через типы. Это не общий тип как таковой. Его часто называют ассоциированным типом, и он определяется, когда протокол принимается типом.

[свернуть]

Вопрос №3 – Swift 1.0 и далее

Иногда собеседование iOS включает каверзные вопросы вроде этого.

В Objective-C константу можно объявить следующим образом:

Это вариант для Swift:

Есть ли разница между ними? Если да, можете ли вы объяснить, как они отличаются?

Решение внутри

Константа – это переменная, инициализированная значением времени компиляции или выражением, разрешенным во время компиляции.

Константа, созданная через let, не обязательно должна принимать значение во время компиляции, однако условие все-таки есть: значение может быть определено только один раз.

[свернуть]

Вопрос №4 – Swift 1.0 и далее

Чтобы объявить статическое свойство или функцию, используйте модификатор static. На примере структуры:

Для классов можно использовать либо static, либо модификатор class. Они достигают одной и той же цели, но на самом деле разные. Можете ли вы объяснить, чем они отличаются?

Решение внутри

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

При применении к классам static становится псевдонимом для class final. Например, в этом коде компилятор будет жаловаться, когда вы попытаетесь переопределить illuminate():

[свернуть]

Вопрос №5 – Swift 1.0 и далее

Можете ли вы добавить сохраненное свойство с помощью расширения? Объясните.

Решение внутри

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

[свернуть]

Продвинутый уровень

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

Вопрос №1 – Swift 1.2

Объясните проблему в Swift 1.2, связанную с объявлением перечисления с дженерик-типами. Возьмем, например, перечисление Either с двумя дженерик-типами T и V. При этом T используется как связанный тип значения для Left, а V – для Right:

Решение внутри

Ошибка компиляции со следующим (загадочным) сообщением об ошибке:

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

Эта проблема была решена в версии Swift 2.0.

[свернуть]

Вопрос №2 – Swift 1.0 и далее

Замыкающие выражения – это элементы (значения) или ссылочные типы?

Решение внутри

Замыкающие выражения – это ссылочные типы.

[свернуть]

Вопрос №3 – Swift 1.0 и далее

Тип UInt используется для хранения целых чисел без знака. Он реализует инициализатор для преобразования:

Однако следующий код генерирует исключение ошибки, если вы указываете отрицательное значение:

Зная, что отрицательное число внутренне представлено, и используя два дополнения в качестве положительного числа, как можно преобразовать отрицательное число Int в UInt, сохраняя при этом представление своей памяти?

Решение внутри

Для этого есть инициализатор:

[свернуть]

Вопрос №4 – Swift 1.0 и далее

Опишите ситуацию, когда можно получить циклическую ссылку в Swift?

Решение внутри

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

Вы решите проблему, заменив одну из сильных ссылок на weak или unowned.

[свернуть]

Вопрос №5 – Swift 2.0 и далее

В Swift 2.0 есть ключевое слово для создания рекурсивных перечислений. Пример:

Что это за ключевое слово?

Решение внутри

Это ключевое слово indirect, которое допускает рекурсивные случаи перечисления следующим образом:

[свернуть]

Поздравляем с успешно пройденным материалом! Теперь даже самое сложное собеседование iOS вам по плечу.-




1 комментарий