Можно ли кодировать подкласс NSManagedObject?
Это приложение для iPhone, но я не думаю, что это действительно важно. Мне нужно отправить пользовательский объект (который управляется Core Data) через Bluetooth с помощью iPhone GameKit. Обычно я просто использовал NSKeyedArchiver для упаковки объекта в качестве объекта данных и отправки его по линии, а затем разархивировать объект, и я закончен. Конечно, мне нужно было бы реализовать методы initWithCoder: и encodeWithCoder: в моем пользовательском объекте.
Я не уверен, что это можно сделать с помощью класса NSManagedObject, который управляется Core Data или нет. Будут ли они играть вместе? Я предполагаю, что когда я отправляю закодированный управляемый объект на другое устройство и unencode его, я просто добавлю этот полученный объект к другому контексту устройства. Это верно? Не хватает ли каких-либо шагов?
Ответы
Ответ 1
Экземпляр NSManagedObject
не может содержательно существовать вне экземпляра NSManagedObjectContext
, поэтому я не стал бы пытаться выполнять танцы NSCoding
, необходимые для непосредственного сериализации и десериализации NSManagedObject
между двумя контекстами (вы может это сделать, см. ниже). Вместо этого я бы создал словарь с соответствующим ключом/значением атрибута (вы можете получить имена атрибутов через имена атрибутов экземпляра управляемого объекта через instance.entity.attributesByName.allKeys
(вы можете использовать [instance dictionaryWithValuesForKeys:keys]
для получения словаря атрибутов: пары значений). я будет передавать информацию о соединении как NSURL
-encoded NSManagedObjectIDs
. Не забудьте включить экземпляр managedObjectID
(как NSURL
) в словарь, чтобы вы могли повторно подключить любые отношения к объекту на другом конце. Вам придется рекурсивно создавать эти словари для любых целей отношений для экземпляра, который вы кодируете.
Затем отправьте dict по проводу и восстановите их на другом конце как экземпляры в новом контексте управляемых объектов (вы можете использовать setValuesForKeysWithDictionary:
).
Вы можете заметить, что именно это будет делать система NSCoder
, за исключением того, что вам нужно будет использовать classForCoder
, replacementObjectForCoder:
и awakeAfterUsingCoder:
вместе с пользовательским подклассом NSDictionary
для обработки всех отображение NSManageObject
-to- NSDictionary
и наоборот. Этот код вызывает больше проблем, чем это стоит, по моему опыту, если у вас нет сложного/глубокого графа объектов, который вы пытаетесь сериализовать. Для одного экземпляра NSManagedObject
без связей нет необходимости просто конвертировать в dict и обратно.
Ответ 2
Это звучит как работа для TPAutoArchiver.
Ответ 3
Я предлагаю словарное решение для более простых опций. Однако, вот как я решил проблему. Моя модель была уже значительной и надежной, с пользовательскими классами и одним корневым классом выше NSManagedObject
.
Все, что мне было нужно, было для того, чтобы этот единственный класс вызывал соответствующий назначенный инициализатор NSManagedObject
: [super initWithEntity:insertIntoManagedObjectContext:]
. Этот метод, а метаданные в NSEntityDescription
- это то, что устанавливает реализации всех динамических аксессуаров.
- (id)initWithCoder:(NSCoder *)aDecoder {
CoreDataStack *cds = [LibraryDiscoverer unarchivingCoreDataStack];
NSEntityDescription *entity = [cds entityDescriptionForName:[[self class] entityName]];
NSManagedObjectContext *moc = [cds managedObjectContext];
self = [super initWithEntity:entity insertIntoManagedObjectContext:moc];
self.lastEditDate = [aDecoder decodeObjectForKey:@"lastEditDate"];
return self;
}
CoreDataStack
- это моя абстракция вокруг CoreData. LibraryDiscoverer
- это глобальный крючок доступа для получения информации о базовых данных. entityName
- это метод, определяемый для предоставления имени сущности из имени класса; если вы соблюдаете соглашение об именах (например, имя класса = имя объекта), оно может быть реализовано в целом.
Все остальные методы initWithCoder:
в моей иерархии классов являются стандартными NSCoder
, с примечанием о том, что вам не нужно кодировать оба направления отношений, CoreData повторно соединяет это для вас. (Как всегда, в том числе со словарным решением.)