2012-04-04 4 views
2

В основном я использую некоторый открытый исходный код под названием OrderedDictionary, который является производным от NSMutableDictionary. Затем я хочу сохранить упорядоченные словарные данные в NSUserDefaults, добавив метод кодирования и декодирования в класс OrderedDictionary. Однако я понял, что методы кодирования и декодирования не вызываются, в результате декодированный словарь больше не упорядочивается. Ниже мой код:encodeWithCoder не вызывается в производном классе NSMutableDictionary

@interface OrderedDictionary : NSMutableDictionary <NSCopying, NSCoding> 
{ 
    NSMutableDictionary *dictionary; 
    NSMutableArray *array; 
} 

В файле реализации:

/** 
* encode the object 
**/ 
- (void)encodeWithCoder:(NSCoder *)coder 
{ 
    [super encodeWithCoder:coder]; 
    [coder encodeObject:dictionary forKey:@"dictionary"]; 
    [coder encodeObject:array forKey:@"array"]; 
} 

/** 
* decode the object 
*/ 
- (id)initWithCoder:(NSCoder *)coder 
{ 
    self = [super initWithCoder:coder]; 
    if (self != nil) 
    { 
     dictionary = [coder decodeObjectForKey:@"dictionary"]; 
     array = [coder decodeObjectForKey:@"array"]; 
    } 
    return self; 
} 

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

dictionary = [[OrderedDictionary alloc] init]; 
[dictionary setObject:@"one" forKey:@"two"]; 
[dictionary setObject:@"what" forKey:@"what"]; 
[dictionary setObject:@"7" forKey:@"7"]; 
NSLog(@"Final contents of the dictionary: %@", dictionary); 

if ([[NSUserDefaults standardUserDefaults] objectForKey:@"myDictionary"] == nil) 
{ 
    [[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:dictionary] 
              forKey:@"myDictionary"]; 
} 
else 
{ 
    NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults]; 

    NSData *savedDictionary = [currentDefaults objectForKey:@"myDictionary"]; 

    if (savedDictionary != nil) 
    { 
     OrderedDictionary *oldData = [NSKeyedUnarchiver unarchiveObjectWithData:savedDictionary]; 
     if (oldData != nil) 
     { 
      NSLog(@"Final contents of the retrieved: %@", oldData); 

     } 
    } 
} 

Дело в том, окончательное retrievedDictionary не имеет оригинал порядок данных и методы кодирования и декодирования вообще не вызываются.

Спасибо за любую помощь заранее! :)

+0

Я подозреваю, что нет никакого способа, чтобы исправить это, то мы не можем быть в состоянии назвать кодирования и декодирования методов класса ребенка в NSMutableDictionary .... – trillions

ответ

3

Там есть метод NSObject называется -classForCoder, что вам необходимо изменить в OrderedDictionary. Из документов:

classForCoder
Переопределена подклассами, чтобы заменить класс, кроме его собственного во время кодирования.

- (класс) classForCoder
Возвращаемое значение
Класс для замены собственного класса приемника во время кодирования.

Обсуждение
Этот метод вызывается NSCoder. Исполнение NSObject возвращает класс приемника. Частные подклассы кластера кластера заменяют имя своего публичного суперкласса при архивировании .

Это последняя строка - это ключ. Так, в OrderedDictionary.m:

- (Class)classForCoder 
{ 
    return [self class]; // Instead of NSMutableDictionary 
} 

Кроме того, если вы не используете ARC, убедитесь, что вы сохраняете объекты, возвращающиеся из -decodeObjectForKey. Как упоминается rob mayoff ниже, вы не должны звонить [super initWithCoder:] (или [super encodeWithCoder:'). Я также изменил ключевые строки, чтобы избежать столкновений.

- (id)initWithCoder:(NSCoder *)coder 
{ 
    if (self != nil) 
    { 
     dictionary = [[coder decodeObjectForKey:@"OrderedDictionary_dictionary"] retain]; 
     array = [[coder decodeObjectForKey:@"OrderedDictionary_array"] retain]; 
    } 
    return self; 
} 
+0

Ему также необходимо избегать вызова '[super initWithCoder:]', если он также не реализовал 'initWithObjects: forKeys: count:' или он сработает. И если он не называет '[super initWithCoder:]', то он также не должен вызывать '[super encodeWithCoder:]'. –

+0

Спасибо, что поймали эту грацию. Отредактировал мой ответ, чтобы включить его. –

+0

@AndrewMadsen Я протестировал изменения, которые вы сделали, отлично поработал! Спасибо огромное! Не следует ли добавить этот ответ к исходному коду OrderedDictionary? :) – trillions

0

Возможно, вы создали новый OrderedDictionary с неправильным инициализатором, initWithDictionary:. Попробуйте вместо этого:

OrderedDictionary *oldData = [NSKeyedUnarchiver unarchiveObjectWithData: savedDictionary]; 
if (oldData != nil) 
{ 
    NSLog(@"Final contents of the retrieved: %@", oldData); 
} 

Убедитесь, что initWithDictionary: ожидает OrderedDictionary в качестве аргумента. Я предполагаю, что он ожидает NSDictionary.

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

OrderedDictionary *myDict = ...; 
NSData* data = [NSKeyedArchiver archivedDataWithRootObject: myDict]; 
[[NSUserDefaults standardDefaults] setObject: data forKey: @"myDictionary"]; 
+0

спасибо за вашу помощь.Я просто пробовал свой путь. Выход по-прежнему не подходит, заказ данных больше не сохраняется. Я обновил свой код в этом сообщении, чтобы отразить сделанное вами изменение. Я думаю, что проблема в том, что мой encodeWithCoder не был вызван вообще, так что были вызваны методы кодирования и декодирования в родительском классе (NSMutableDictionary). Однако я не знаю, как это исправить. – trillions

+0

Убедитесь, что вы используете 'NSKeyedArchiver' при сохранении значений по умолчанию. Поместите 'NSLog()' в 'initWithCoder:' и 'encodeWithCoder:', чтобы проверить, правильно ли они вызваны и работают. – Costique

+0

Я отредактировал ответ, чтобы включить код архивации. – Costique

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