> Может ли dataCompanies быть nil при декодировании JSON в Swift? (iOS, Swift)

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

Компании: Ozon

Стек: iOS, Swift

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

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

Да, может, но не из-за самого JSON. если dataCompanies объявлен как non-optional свойство, то JSONDecoder не присвоит ему nil напрямую: при отсутствии ключа или null декодирование упадёт с ошибкой keyNotFound или valueNotFound. nil в рантайме возможен только если свойство optional, инициализировано вручную или используется кастомный init(from:), который явно выставляет nil.

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

В Swift JSONDecoder работает через Decodable и init(from:). Для non-optional свойства типа [Company] декодер ожидает, что ключ есть и значение не null. Иначе выбрасывается DecodingError:

  • keyNotFound, если ключа нет;

  • valueNotFound, если значение null;

  • typeMismatch, если тип не совпадает.

Если свойство объявлено как [Company]?, то null или отсутствие ключа дадут nil без ошибки. Но это уже свойство модели, а не поведение JSON. Также nil может появиться, если модель создаётся не через декодер, а вручную, или если кастомный init(from:) присваивает nil при определённых условиях.

Важный нюанс: decodeIfPresent не делает non-optional свойство optional. Он возвращает optional, и дальше нужно решить, что делать: присвоить значение по умолчанию, выбросить ошибку или оставить nil в optional свойстве.

На практике

На senior-уровне важно разделять три вещи:

  1. контракт API: ключ обязателен или опционален;

  2. модель: свойство optional или нет;

  3. стратегия декодирования: строгая или мягкая.

Если API может не вернуть dataCompanies, а бизнес-логика это допускает, свойство делают optional или задают default []. Если поле обязательное, лучше оставить non-optional и дать декодированию упасть, чтобы ошибка была явной. смешивать эти подходы без причины - источник багов.

Пример кода

SWIFT
struct Response: Decodable {
let dataCompanies: [Company] // non-optional
}
// JSON без ключа -> keyNotFound
// JSON с null -> valueNotFound
struct ResponseOptional: Decodable {
let dataCompanies: [Company]? // null или отсутствие ключа -> nil
}
struct ResponseDefault: Decodable {
let dataCompanies: [Company]
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
dataCompanies = try container.decodeIfPresent([Company].self, forKey: .dataCompanies) ?? []
}
}

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

Сначала уточните, что значит "может ли быть nil": в JSON, в модели или в рантайме. Затем объясните поведение JSONDecoder для non-optional и optional свойств, упомяните DecodingError и decodeIfPresent. В конце добавьте, что решение зависит от контракта API и бизнес-требований, а не только от синтаксиса Swift.

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

Понимание difference между optional в модели и null в JSON, знание DecodingError, умение выбирать между строгим и мягким декодированием, а также способность отделять контракт API от реализации модели.

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

  • считать, что non-optional свойство может стать nil при декодировании;

  • путать decode и decodeIfPresent;

  • делать все поля optional "на всякий случай", теряя явность контракта;

  • игнорировать keyNotFound и valueNotFound как разные сценарии;

  • использовать try? вокруг всего декодирования и терять причину ошибки.

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

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