> Как реализовать функции setValue и getValue с поддержкой nil значений (iOS, Swift)

Уровень: senior · Роль: mobile · Категория: Технические вопросы

Компании: Revolut

Стек: iOS, Swift

> Пример ответа

Короткий ответ

Для поддержки nil значений в setValue/getValue нужно использовать Optional (?) в сигнатуре методов и отличать "ключ отсутствует" от "значение nil". Хранение лучше организовать через словарь [Key: Value], где Value - Optional, а доступ через subscript с проверкой наличия ключа. В Swift это естественно решается через enum с ассоциированными значениями или через Dictionary с Optional значениями и отдельным флагом существования ключа.

Подробное объяснение

Проблема возникает из-за того, что Dictionary[Key] возвращает Value?, где nil означает и отсутствие ключа, и хранимое nil-значение. Для различения этих случаев нужно хранить Optional внутри Optional: [Key: Value?]. Тогда:

  • dict[key] == nil - ключ отсутствует
  • dict[key] == .some(nil) - ключ есть, значение nil
  • dict[key] == .some(.some(value)) - ключ есть, значение есть

Альтернативный подход - использовать enum Storage<Value> { case absent, present(Value?) } и словарь [Key: Storage<Value>]. Это более явно и типобезопасно.

Для setValue/getValue сигнатуры:

SWIFT
func setValue(_ value: Value?, forKey key: Key)
func getValue(forKey key: Key) -> Value??

Второй возвращает Value?? - внешний Optional говорит о наличии ключа, внутренний - о значении.

На практике

В реальном iOS-коде такая задача возникает при работе с UserDefaults, кэшами или конфигурационными хранилищами, где нужно отличать "не задано" от "задано как nil". Часто используют обёртку PropertyWrapper или generic-класс хранилища.

Для UserDefaults есть нюанс: set(nil, forKey:) удаляет ключ, поэтому для хранения nil нужно использовать sentinel-значение (например, специальную строку) или отдельный словарь флагов.

Пример кода

SWIFT
struct KeyValueStore<Key: Hashable, Value> {
private var storage: [Key: Value?] = [:]
mutating func setValue(_ value: Value?, forKey key: Key) {
storage[key] = value
}
func getValue(forKey key: Key) -> Value?? {
return storage[key] // .some(nil) - ключ есть, nil; .none - ключа нет
}
func hasKey(_ key: Key) -> Bool {
return storage[key] != nil
}
}
// Использование
var store = KeyValueStore<String, Int>()
store.setValue(nil, forKey: "a")
store.setValue(5, forKey: "b")
let a = store.getValue(forKey: "a") // Optional(Optional(nil))
let b = store.getValue(forKey: "b") // Optional(Optional(5))
let c = store.getValue(forKey: "c") // nil
switch store.getValue(forKey: "a") {
case .some(.some(let value)): print("value: \(value)")
case .some(.none): print("key exists, value is nil")
case .none: print("key missing")
}

Как отвечать на собеседовании

Начни с постановки проблемы: Dictionary не различает отсутствие ключа и nil-значение. Затем предложи два решения: [Key: Value?] и enum Storage. Объясни trade-off: первый проще, второй - безопаснее и читаемее. Покажи сигнатуры с Value?? и объясни семантику каждого уровня Optional. Упомяни, что в SwiftUI/Combine часто используют Published<Value?> с отдельным флагом наличия. Если спросят про UserDefaults - расскажи про sentinel-значения.

Что проверяет интервьюер

  • Понимание Optional-вложенности и её семантики
  • Умение проектировать API с учётом edge case
  • Знание Swift-типов и их поведения (Dictionary, Optional)
  • Способность объяснить trade-off между простотой и типобезопасностью
  • Практическое мышление: как это применить в реальном iOS-коде

Типичные ошибки

  • Использование [Key: Value] без учёта nil - потеря информации о наличии ключа
  • Возврат Value? вместо Value?? - невозможно отличить "нет ключа" от "nil"
  • Забывают, что dict[key] = nil удаляет ключ, а не сохраняет nil
  • Путают .some(nil) и nil при switch по Optional
  • Не учитывают, что Dictionary subscript с default параметром тоже не решает проблему различения
  • Предлагают хранить NSNull как маркер - это не Swift-идиоматично и ломает типобезопасность

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью