Для чего нужен ObjectIdentifier в Swift
Что проверяют
Понимаете ли вы разницу между идентичностью объекта и равенством по значению в Swift. Следом часто спрашивают, чем ObjectIdentifier отличается от оператора === и что станет с идентификатором после освобождения объекта.
Как отвечать
ObjectIdentifier это лёгкая структура поверх адреса экземпляра класса или метатипа. Она Hashable и Comparable, поэтому годится как ключ словаря или элемент Set, даже если сам класс протоколу Hashable не соответствует.
Где применяется:
- идентичность вместо равенства: чтобы класс стал
Hashableпо ссылке, в==сравниваютlhs === rhs, а вhash(into:)передаютObjectIdentifier(self); - реестры по типу:
ObjectIdentifier(T.self)даёт ключ для самого типа. Так устроены простые DI-контейнеры и кэши фабрик, где зависимость ищут по её типу; - списки наблюдателей: словарь из
ObjectIdentifierв обёртку со слабой ссылкой позволяет подписать объект и отписать его, не требуя от подписчика никаких протоколов; Identifiableдля классов: стандартная библиотека даёт классам реализациюidпо умолчанию именно черезObjectIdentifier, этим пользуется SwiftUI вForEachиList.
Для прямого сравнения двух ссылок достаточно ===. ObjectIdentifier нужен там, где идентичность надо сохранить как значение: положить в коллекцию, передать дальше, отсортировать.
Главное свойство, которое стоит проговорить: идентификатор объект не удерживает. Он не увеличивает счётчик ссылок, но и не следит за жизнью объекта. Пока экземпляр жив, идентификатор уникален. После освобождения память может занять новый объект, и его ObjectIdentifier совпадёт со старым.
Где спотыкаются
Используют ObjectIdentifier как постоянный ключ для объектов, которые никто не держит. Объект ушёл, адрес переиспользовали, и кэш возвращает чужие данные.
Пытаются получить его для структуры. Инициализатор принимает только экземпляр класса или метатип: у значимых типов идентичности нет, есть только равенство.
Сохраняют его в базу данных или отправляют на сервер как идентификатор записи. Это адрес в памяти текущего процесса, после перезапуска приложения он ничего не значит.