Указатели на существующие объекты после encodeWithCoder: и initWithCoder:

Как NSCoding справляется с кодированием и декодированием указателей на другие объекты, а не на значения? У меня есть ряд классов моделей, которые мне нужно закодировать, и они должны ссылаться друг на друга со слабыми свойствами. Я был удивлен, обнаружив, что ссылки, похоже, сохраняются после кодирования, сохранения в файл, последующего чтения из файла и декодирования. Это работало даже несмотря на то, что адреса памяти объектов, которые ссылались друг на друга, изменились. Мне интересно узнать, как NSCoding достигает этого, а также хочу убедиться, что он будет работать последовательно.

Короче говоря: если я кодирую свойства, содержащие указатели на другие объекты, могу ли я на 100% полагаться на ссылки, сохраняемые после декодирования?


person mashers    schedule 27.01.2018    source источник


Ответы (1)


tl;dr: Да, NSKeyedArchiver и NSKeyedUnarchiver поддерживают ссылочные отношения объектов в графе объектов; если вы кодируете граф объектов, где объекты ссылаются на другие объекты, вы можете ожидать, что граф будет декодирован таким образом, чтобы поддерживать эти отношения. Вы не обязательно получите те же самые указатели после кодирования и декодирования, но идентификаторы объектов останутся прежними.


Когда вы кодируете объект через -encodeObject:forKey:, NSKeyedArchiver никогда не записывает адрес указателя объекта. Вместо этого он поддерживает уникальную таблицу объектов, которые он видел раньше:

  1. Если объект, который вы кодируете, никогда раньше не видели, он добавляется в таблицу и ему присваивается UID. Затем у него вызывается -encodeWithCoder:, чтобы он мог кодировать все свои свойства.
  2. Если он был замечен ранее (и ему был присвоен UID), ничего не происходит (но вместо него записывается UID)

Когда архивирование завершено, архив содержит уникальную таблицу объектов, а также еще один словарь, представляющий структуру графа объектов. Вместо объектов используются UID.

При декодировании, когда вы переходите к вызову -decodeObject:forKey:, NSKeyedUnarchiver выполняет обратное сопоставление:

  1. Он просматривает UID ключа в архиве и ищет UID в уникальной таблице. Если этот объект был декодирован ранее, он возвращает ссылку на декодированный объект. Это ключевая часть — вы не обязательно получите тот же самый указатель при декодировании, который был закодирован при кодировании, но вы получите ссылку на тот же объект вместо копия
  2. Если UID никогда ранее не декодировался, он ищет закодированный объект в уникальной таблице, соответствующей UID, ищет класс и вызывает +alloc, -initWithCoder: и -awakeAfterUsingCoder для объекта. Затем объект записывается в карту UID-to-object для повторного использования при необходимости.

Это одна из ключевых особенностей системы архиватора с ключом, и вы можете быть уверены, что такое поведение сохранится.

person Itai Ferber    schedule 27.01.2018
comment
Спасибо за это увлекательное объяснение. Это имело смысл, и я уверен, что теперь могу на это положиться. Чем больше я узнаю о Cocoa и Objective-C, тем больше они мне нравятся. Я разрабатываю приложения для iOS уже 8 лет и все еще учусь :) - person mashers; 28.01.2018
comment
@mashers Отлично! :) Рад, что помог. - person Itai Ferber; 28.01.2018