Подтвердить что ты не робот

Можно ли кодировать подкласс NSManagedObject?

Это приложение для iPhone, но я не думаю, что это действительно важно. Мне нужно отправить пользовательский объект (который управляется Core Data) через Bluetooth с помощью iPhone GameKit. Обычно я просто использовал NSKeyedArchiver для упаковки объекта в качестве объекта данных и отправки его по линии, а затем разархивировать объект, и я закончен. Конечно, мне нужно было бы реализовать методы initWithCoder: и encodeWithCoder: в моем пользовательском объекте.

Я не уверен, что это можно сделать с помощью класса NSManagedObject, который управляется Core Data или нет. Будут ли они играть вместе? Я предполагаю, что когда я отправляю закодированный управляемый объект на другое устройство и unencode его, я просто добавлю этот полученный объект к другому контексту устройства. Это верно? Не хватает ли каких-либо шагов?

4b9b3361

Ответ 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 повторно соединяет это для вас. (Как всегда, в том числе со словарным решением.)