Как реализовать хранение и обновление данных с использованием словаря
Что проверяют
Базовые операции со Dictionary в Swift и понимание, как он ведёт себя как тип значения. Следом почти всегда спрашивают про многопоточность: что будет, если словарь обновляют из нескольких мест сразу.
Как отвечать
Покажите операции и то, что они возвращают:
- запись и обновление:
dict[id] = userдобавляет или заменяет.updateValue(user, forKey: id)делает то же, но возвращает старое значение илиnil, так удобно отличить вставку от обновления; - удаление:
dict[id] = nilилиremoveValue(forKey:), второй вернёт удалённое значение; - значение по умолчанию:
counts[word, default: 0] += 1без проверки на существование ключа; - правка на месте:
users[id]?.name = "Анна"меняет поле структуры внутри словаря и ничего не делает, если ключа нет; - слияние:
merge(_:uniquingKeysWith:)объединяет со вторым словарём по явному правилу для конфликтующих ключей; - группировка:
Dictionary(grouping: items, by: \.category)строит индекс за один проход.
Ключ должен быть Hashable, операции в среднем O(1), порядок обхода не гарантирован. Если порядок важен, храните отдельный массив ключей или берите OrderedDictionary из пакета swift-collections.
Dictionary это тип значения с копированием при записи: присвоение другой переменной дешёвое, а реальная копия появится при первой мутации. Поэтому изменения в копии, переданной в функцию, в оригинал не попадают, если параметр не inout.
Состояние держат не в глобальной переменной, а в типе. Для доступа из разных потоков подойдёт actor UserStore с методами upsert и remove: обращения к нему сериализуются, и гонку данных компилятор не пропустит. В режиме Swift 6 глобальная изменяемая переменная без изоляции уже ошибка компиляции.
Где спотыкаются
Обновляют словарь из нескольких потоков без синхронизации. Dictionary не потокобезопасен, и это приводит к падениям, которые трудно воспроизвести.
Ожидают, что словарь сохраняет порядок вставки, и строят на нём список в интерфейсе. От запуска к запуску порядок может меняться.
Путают удаление и запись nil: у словаря [String: Int?] присваивание nil удаляет ключ, а не сохраняет пустое значение.