2012-02-24 4 views
0

Я пытаюсь сохранить мой графический объект в файл, а затем перезагрузить его позже, однако decodeObjectForKey: всегда возвращает nil для любого ключа, который я указываю.decodeObjectForKey: всегда возвращает nil

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

Я пропустил, понял, как работают NSKeyedArchiver и NSKeyedUnarchiver? Любая помощь будет оценена по достоинству.

- (void)encodeWithCoder:(NSCoder *)encoder { 
    [encoder encodeFloat:titleFontSize forKey:@"titleFontSize"]; 
    [encoder encodeObject:[UIColor orangeColor] forKey:@"titleTextColor"]; 
    [encoder encodeObject:lineSeparatorColor forKey:@"lineSeparatorColor"]; 
    [encoder encodeObject:bodyTextColor forKey:@"bodyTextColor"]; 
    [encoder encodeFloat:bodyTextFontSize forKey:@"bodyTextFontSize"]; 
    [encoder encodeObject:backgroundColor forKey:@"backgroundColor"]; 
    [encoder encodeObject:tintColor forKey:@"tintColor"]; 
    [encoder encodeInteger:bodyTextAlignment forKey:@"bodyTextAlignment"]; 

    [encoder encodeObject:@"Text" forKey:@"Text"]; 
} 

+ (void) saveToFile { 
    // Get the shared instance 
    PSYDefaults *sharedInstance = [PSYDefaults sharedInstance];  

    // Serialise the object 
    NSData *serializedObject = [NSKeyedArchiver archivedDataWithRootObject:sharedInstance]; 

    // Get the path and filename of the file 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; 
    NSString *pathAndFileName = [documentsDirectory stringByAppendingPathComponent:ksDefaultsFileName]; 

    // Write the defaults to a file 
    if (serializedObject) [serializedObject writeToFile:pathAndFileName atomically:YES]; 
} 

+ (void) loadFromFile { 
    // Get the shared instance 
    PSYDefaults *sharedInstance = [PSYDefaults sharedInstance];  

    // Get the path and filename of the file 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; 
    NSString *pathAndFileName = [documentsDirectory stringByAppendingPathComponent:ksDefaultsFileName]; 

    NSData *codedData = [[[NSData alloc] initWithContentsOfFile:pathAndFileName] autorelease]; 
    NSKeyedUnarchiver *defaults = [[NSKeyedUnarchiver alloc] initForReadingWithData:codedData]; 

    // Set the properties of the shared instance 
    NSString *test = [defaults decodeObjectForKey:@"Text"]; 
    NSLog (@"%@", test); 
    sharedInstance.titleTextColor = [defaults decodeObjectForKey:@"titleTextColor"]; 

    [defaults release]; 
} 

EDIT: на основе рекомендаций от DarkDust:

- (id)initWithCoder:(NSCoder *)aDecoder { 
    self = [super init]; 
    if (self) { 
     self.titleFontSize = [[aDecoder decodeObjectForKey:@"titleFontSize"] floatValue]; 
     self.titleTextColor = [aDecoder decodeObjectForKey:@"titleTextColor"]; 
     self.lineSeparatorColor = [aDecoder decodeObjectForKey:@"lineSeparatorColor"]; 
     self.bodyTextColor = [aDecoder decodeObjectForKey:@"bodyTextColor"]; 
     self.bodyTextFontSize = [[aDecoder decodeObjectForKey:@"bodyTextFontSize"] floatValue]; 
     self.backgroundColor = [aDecoder decodeObjectForKey:@"backgroundColor"]; 
     self.tintColor = [aDecoder decodeObjectForKey:@"tintColor"]; 
     self.bodyTextAlignment = [[aDecoder decodeObjectForKey:@"bodyTextAlignment"] intValue]; 
    } 
    return self; 
} 

и создание нового экземпляра просто тест:

+ (void) loadFromFile { 
    // Get the shared instance 
    PSYDefaults *sharedInstance = [PSYDefaults sharedInstance];  

    // Get the path and filename of the file 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; 
    NSString *pathAndFileName = [documentsDirectory stringByAppendingPathComponent:ksDefaultsFileName]; 

    NSData *codedData = [[[NSData alloc] initWithContentsOfFile:pathAndFileName] autorelease]; 
    PSYDefaults *newInstance = [NSKeyedUnarchiver unarchiveObjectWithData:codedData]; 

    sharedInstance.titleTextColor = newInstance.titleTextColor; 
} 

EDIT - Update (требуется для кодирования поплавки и ints как NSNumbers)

- (void)encodeWithCoder:(NSCoder *)encoder { 
    [encoder encodeObject:[NSNumber numberWithFloat:titleFontSize] forKey:@"titleFontSize"]; 
    [encoder encodeObject:titleTextColor forKey:@"titleTextColor"]; 
    [encoder encodeObject:lineSeparatorColor forKey:@"lineSeparatorColor"]; 
    [encoder encodeObject:bodyTextColor forKey:@"bodyTextColor"]; 
    [encoder encodeObject:[NSNumber numberWithFloat:bodyTextFontSize] forKey:@"bodyTextFontSize"]; 
    [encoder encodeObject:backgroundColor forKey:@"backgroundColor"]; 
    [encoder encodeObject:tintColor forKey:@"tintColor"]; 
    [encoder encodeObject:[NSNumber numberWithInt:bodyTextAlignment] forKey:@"bodyTextAlignment"]; 
} 

ответ

6

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

Вы хотите unarchiveObjectWithData:, как:

NSData *codedData = [[[NSData alloc] initWithContentsOfFile:pathAndFileName] autorelease]; 
PSYDefaults *decodedDefaults = [NSKeyedUnarchiver unarchiveObjectWithData:codedData]; 

Обратите внимание, что вы также должны реализовать initWithCoder: в качестве аналога для encodeWithCoder:. Несмотря на то, что вам кажется, что здесь нужен один синглтон, NSCoding требует создать новый объект здесь из-за [NSKeyedArchiver archivedDataWithRootObject:sharedInstance].

Если вы хотите ан/декодировать поля без создания нового экземпляра PSYDefaults, то вам нужно использовать -[NSKeyedArchiver initForWritingWithMutableData:] и передать этот архив к способу, похожему на ваш encodeWithCoder: (но вы должны дать ему другое имя, то). Затем вы должны написать коллегу, которая читает поля обратно через NSKeyedUnarchiver, где вы используете decodeObjectForKey: и друзей для каждого поля.

Возможно, вам также захочется прочитать статью от Apple Archives and Serializations Programming Guide.

+0

Это отличный совет, спасибо. Я осознал свою глупость с unarchiving и теперь создаю новый экземпляр и внедрил initWithCoder. Я думаю, что я почти там, initWithCoder вызывается, когда NSKeyedUnarchiver распаковывает мой графический объект. Однако я получаю плохой доступ после вызова initWithCoder любых идей? Dave –

+0

Doh, скраб это. Проблема с выпуском newInstance, когда он уже автореализован. Спасибо за вашу помощь! Дейв –

1

Попытки сохранить объект с помощью:

[NSKeyedArchiver archiveRootObject:object toFile:filePath]; 

и загрузить его с помощью:

[NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; 

Я использую выше методы, чтобы сохранить NSDictionary с пользовательским объектом в файл.

А также вы должны иметь функцию initWithCoder: (NSCoder *) декодер в вашем объекте. Какие декодировать данные с помощью

[decoder decodeObjectFoyKey:yourKey]; 
+0

Спасибо Hanon, DarkDust отсортированы в конце. Дайте ответ +1 за помощью. –

0

У меня была другая проблема с NSCoder'sdecodeObjectForKey метод при использовании FXForm - он разбился без каких-либо объяснений.

- (id)initWithCoder:(NSCoder *)decoder 
{ 
    if (self = [super init]) { 
    self.someObject = [decoder decodeObjectForKey:@"someObject"]; 
    } 
    return self; 
} 

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

@interface MyClass : : NSObject <FXForm, NSCoding> 

@property (nonatomic, copy) SomeClass *someObject; 

@end 

На всякий случай кто-то встретит эту проблему.

Смежные вопросы