Сохранение CoreData-сущностей в NSUserDefaults

Представьте себе объект CoreData (например, с именем searchEngine).
NSManagedObjectContext управляет некоторыми «экземплярами» этого объекта.
Конечный пользователь сможет выбрать свой "standard searchEngine" с помощью NSPopupButton.
selected object NSPopupButton должен быть привязан к NSUserDefaults.
Проблема:

1) @ попробовать {сохранить}

a) If you try to save the selected "instance" directly to NSUserDefaults there comes something like this:

-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value ' (entity: searchEngine; id: 0x156f60  ; data: {
    url = "http://google.de/";
    someAttribute = 1;
    name = "google";
})' of class 'searchEngine'.

b) If you try to convert the "instance" to NSData comes this:

-[searchEngine encodeWithCoder:]: unrecognized selector sent to instance 0x1a25b0

Итак, есть идеи, как получить эти объекты в данных, совместимых с plist?

2) @ попробовать {registerDefaults}

Обычно метод registerDefaults: реализован в + (void)initialize. Проблема здесь в том, что этот метод вызывается до того, как CoreData загрузит сохраненные сущности из своей базы данных. Итак, я не могу установить значение по умолчанию для несуществующего объекта, верно?

Я знаю, длинные вопросы ... но: попробуйте {[я предоставлю: подробности]}; D


person papr    schedule 01.02.2009    source источник


Ответы (4)


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

Некоторый пример кода (немного измененный из примера, опубликованного в Core Data Programming Руководство):

NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription
    entityForName:@"SearchEngine" inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];

NSPredicate *predicate = [NSPredicate predicateWithFormat:
    @"engineName LIKE[c] '%@'", selectedEngineName];
[request setPredicate:predicate];

NSError *error = nil;
NSArray *array = [moc executeFetchRequest:request error:&error];
if (array == nil)
{
    // Deal with error...
}

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

person Jason Coco    schedule 01.02.2009
comment
Ммм. Вы знаете, почему array != nil но [array count] < 0 ... он не хочет работать ... - person papr; 04.02.2009
comment
Если array! = Nil, то ошибки нет, но также может не быть возвращенных записей ([array count] == ​​0) ... однако [array count] ‹0 может никогда не возникать, поскольку Сообщение count возвращает тип NSUInteger. Компилятор, скорее всего, удалит любой такой тест ([количество массивов] ‹0). - person Jason Coco; 04.02.2009
comment
Ага. Я имел в виду ([количество массивов] == 0). Простите за это. Я только хотел сказать, что в этом массиве ничего нет. ;) - person papr; 05.02.2009

Если вам нужно сохранить ссылку на конкретный управляемый объект, используйте представление URI его идентификатора управляемого объекта:

NSURL *moIDURL = [[myManagedObject objectID] URIRepresentation];

Затем вы можете сохранить URL-адрес по умолчанию.

Чтобы получить управляемый объект, вы используете:

NSManagedObjectID *moID = [myPersistentStoreCoordinator managedObjectIDForURIRepresentation:moIDURL];
NSManagedObject *myManagedObject = [myContext objectWithID:moID];

Единственное предостережение: вы должны убедиться, что исходный идентификатор управляемого объекта постоянен - ​​это не проблема, если вы уже сохранили объект, или вы можете использовать obtainPermanentIDsForObjects:error:.

person mmalc    schedule 07.07.2009
comment
Думаю, это отличное решение. Одно небольшое дополнение, как сказано в документации для NSUserDefaults, вам необходимо архивировать объекты NSURL как NSData. Так что будьте осторожны, чтобы не сохранять NSURL как есть. Я только что сделал эту ошибку и продолжал получать ноль, когда пытался получить объект. Также обратите внимание, что NSUserDefaults имеет метод setURL: forKey :. Однако я не думаю, что в настоящее время это доступно для iPhone OS. - person tilish; 02.02.2010
comment
setURL: forKey: доступен в iOS 4.0 и новее - person djskinner; 24.08.2012
comment
БУДЬТЕ ВНИМАТЕЛЬНЫ! Комментарий Тилиша важен, правильное решение здесь: stackoverflow.com/a/516735/1780492 Без этого вы получите ошибку сообщение: попытка вставить объект, не являющийся списком свойств, x-coredata: - person BootMaker; 03.12.2013

Вот самый чистый и кратчайший способ сделать это в настоящее время с помощью методов setURL и getURL, добавленных в 4.0, чтобы избежать дополнительных вызовов NSKeyedUnarchiver и NSKeyedArchiver:

Сеттер:

 + (void)storeSomeObjectId:(NSManagedObjectID *)objectId
 {
     [[NSUserDefaults standardUserDefaults] setURL:[objectId URIRepresentation] 
                                            forKey:@"someObjectIdKey"];
     [[NSUserDefaults standardUserDefaults] synchronize];
 }

Получатель:

 + (SomeManagedObject *)getObjectByStoredId
 {
     NSURL *uri = [[NSUserDefaults standardUserDefaults] URLForKey:@"someObjectIdKey"];
     NSManagedObjectID *objectId = [self.persistentStoreCoordinator managedObjectIDForURIRepresentation:uri];
     SomeManagedObject *object = [self.managedObjectContext objectWithID:objectId];
 }
person Matt Foley    schedule 28.12.2013

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

public class Patient: NSManagedObject {    
    override public func awakeFromInsert() {
        super.awakeFromInsert()
        uuid = UUID()
}

extension Patient {
    @NSManaged public var uuid: UUID
    @NSManaged ...
}

Рекомендуется идентифицировать каждую запись с помощью уникального идентификатора (UUID). Вы можете сохранить UUID в виде строки, просто вызвав uuid.uuidString.

person AlbertUI    schedule 30.06.2020