NSUserDefaults и условное кодирование пользовательских объектов в NSArray - PullRequest
2 голосов
/ 15 мая 2011

Я знаю, что есть много сообщений, касающихся проблемы архивации пользовательских объектов в NSArray или NSMutableArray и сохранения их в NSUserDefaults.Соответствие протоколу NSCoding и сохранение в NSUserDefaults не является проблематичным, и я довольно часто использую NSUserDefaults для хранения пользовательских данных в моем приложении - в основном это объекты, представляющие Person (давайте назовем подкласс NSObject «Person»), который можетиметь несколько объектов подкласса NSObject «Свойство», хранящихся в NSMutableArray.Поэтому структура данных выглядит следующим образом:

NSMutableArray "persons":
    Person "aPerson":
        NSMutableArray "properties":
            Property "aProperty"
            Property "anotherProperty"
    Person "anotherPerson:
        ...

Архивирование и восстановление информации поначалу не было проблематичным, поскольку и Person, и Property соответствуют протоколу NSCoding - но теперь возникла проблема, которую я не смогрешить еще, несмотря на тысячи запросов Google за последние пару дней;)

Некоторые из объектов Property содержат ссылки на других Persons («Участники», которые связаны с тем же свойством и содержатся в NSMutableArray).).Когда я сохраняю все данные в NSUserDefaults с помощью NSKeyedArchiver, я использую

[aCoder encodeObject:participants forKey:@"participants"];

в методе Property «encodeWithCoder» для архивирования «участников» NSMutableArray, в котором хранятся ссылки на другие объекты Person.Но когда я декодирую эти объекты Person, они создаются новыми и отделяются от объектов Person, которые уже существуют где-то еще.NSMutableArray «участники» содержит только ссылки , слабые ссылки на объекты Person и поэтому должны условно кодировать его содержимое, как это можно сделать с другими объектами вручную в «encodeWithCoder»:

[aCoder encodeConditionalObject:anObject forKey:aKey];

Когда NSMutableArray будет декодирован, он должен представлять список ссылок на уже существующие объекты Person - не полностью новые!Тест "aPerson == [[aDecoder decodeObjectForKey: @" members "] objectAtIndex: 0]" в настоящее время возвращает NO, хотя он вернул YES до того, как произошел процесс кодирования / декодирования.

Я надеюсь, что мое объяснениекак-то понятно, и вы можете помочь мне с моей проблемой :) Простыми словами: как я могу условно кодировать пользовательские объекты, содержащиеся в NSMutableArray?

Спасибо!

Ответы [ 2 ]

1 голос
/ 15 мая 2011

Если NSMutableArray будет использовать encodeConditionalObject:forKey: для содержащихся в нем объектов, это будет просто означать, что эти объекты вообще не кодируются, если они не кодируются безусловно в каком-либо другом месте в вашем графе объектов. Это не поможет вам в этом случае (массив будет пустым).

Проблема в том, что вы не можете кодировать ссылки на объекты в памяти. Ссылка на объект - это просто указатель на адрес в памяти. Когда вы в следующий раз запустите свое приложение и создадите тот же объект (путем разархивирования или иным способом), у него почти наверняка будет другой адрес в памяти. Невозможно «волшебным» образом узнать, какой существующий объект соответствует ссылке, которую он заархивировал, потому что адрес памяти («идентичность») объекта теряет все свое значение при выходе из приложения.

Вы должны использовать другие средства идентификации своих объектов, такие как идентификаторы строк базы данных, ключи словаря и т. Д., И вручную установить соединение архивированного ключа и существующего объекта, соответствующего этому ключу.

0 голосов
/ 24 ноября 2017

У меня тоже была проблема с этим.У меня есть объекты, которые имеют массив слабых ссылок на другие объекты.Я знаю, что все связанные объекты будут закодированы, поэтому я просто хочу убедиться, что могу перестроить ссылки.

С одной слабой ссылкой можно использовать:

aCoder.encodeConditionalObject(thing, forKey: "Thing")

... и если этот элемент уже был закодирован откуда-то еще, то будет использоваться ссылка на этот закодированный элемент.

Но что делать, если у вас есть массив, полный «условных» элементов, гдемассив должен быть закодирован безоговорочно?

В итоге я обернул элементы, на которые хочу связать.

class thingLink: NSObject, NSCoding
{
    weak var thing: Thing?

    init(_ thing: Thing) {
        self.thing = thing
    }

    required init?(coder aDecoder: NSCoder) {
        thing = aDecoder.decodeObject(forKey: "Thing") as? Thing
    }

    func encode(with aCoder: NSCoder) {
        // We encode these conditionally as they must be used elsewhere
        aCoder.encodeConditionalObject(thing, forKey: "Thing")
    }
}

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

aCoder.encode(things, forKey: "Things")

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

...