2013-09-15 1 views
0

Я пытаюсь использовать NSKeyedArchiver/NSKeyedUnarchiver для хранения данных для свойства класса в файле, чтобы сохранить состояние свойства между запусками приложения.Использование NSKeyedArchiver/Unarchiver в пользовательских методах getter/setter

У меня есть свойство, объявленное в MyClass.h как так:

@property (nonatomic, weak) NSDictionary *myDictionary; 

и я создал пользовательские методы получения и установки в MyClass.m, чтобы убедиться, что NSDictionary записывается на диск:

-(NSDictionary *)myDictionary { 
    NSDictionary *dictionary; 

    NSString *path = [self pathToDataStore]; 
    if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { 
     dictionary = [NSDictionary dictionary]; 
    } else { 
     NSData *archivedData = [NSData dataWithContentsOfFile:path]; 
     dictionary = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData]; 
    } 

    return dictionary; 
} 

-(void)setMyDictionary:(NSDictionary *)dictionary { 
    NSString *path = [self pathToDataStore]; 
    NSDictionary *rootObject = [NSDictionary dictionaryWithDictionary:dictionary]; 
    [NSKeyedArchiver archiveRootObject:rootObject toFile:path]; 
    self.myDictionary = dictionary; 
} 

Это вызывает бесконечный цикл вызовов [self setMyDictionary], поэтому я четко делаю что-то неправильно. Но в чем проблема?

ответ

3

вместо:

self.myDictionary = dictionary; 

вы должны сделать:

@synthesize myDictionary; 
... 

-(void)setMyDictionary:(NSDictionary *)dictionary { 

... 
myDictionary = dictionary 
} 

Ваша проблема возникает причина вызова:

self.myDictionary = dictionary; 

равно

[self setMyDictionary:dictionary]; 
+2

+1 Да, но я бы не советовал '@synthesize MyDictionary;', а '@synthesize MyDictionary = _myDictionary,' как использование подчеркиваний стало общепринятой практикой для переменных экземпляра подпирая свойства. Это помогает минимизировать случайные ссылки на ivars, когда вы хотели использовать метод доступа. – Rob

+0

Победа! Я прекратил использовать любой тип '@ synhesize', когда вышел iOS 6, потому что я не видел, где это было необходимо (вместо этого использовал' self.myDictionary' или '_myDictionary'). Я просто добавил '@synthesize myDictionary = _myDictionary', и все работает нормально. – guthook

1

answer from debris объясняет, почему использование синтаксиса self.myDictionary в установщике приводит к бесконечной рекурсии (поскольку этот синтаксис «точка» просто вызывает сеттер снова) и указывает, что вместо этого вы должны использовать переменные экземпляра в методах доступа.

Сказав это, пара дополнительных наблюдений.

  1. Вы можете подтянуть существующий код. Например, почему сеттер создает новый словарь для архивации? Вы можете просто архивировать dictionary, который был передан сеттеру (а также зарегистрировать сообщение, если архив по какой-либо причине не прошел).

    -(void)setMyDictionary:(NSDictionary *)dictionary { 
        if (![NSKeyedArchiver archiveRootObject:dictionary toFile:[self pathToDataStore]]) 
         NSLog(@"%s: archiveRootObject failed", __FUNCTION__); 
        _myDictionary = dictionary; 
    } 
    
  2. Каждый раз, когда вы ссылаетесь на self.myDictionary добытчик, он собирается повторно извлечь из архива, даже если он уже был восстановлен. Это неэффективно и может привести к некоторым непредвиденным последствиям (например, if (self.myDictionary == self.myDictionary)... не удастся). Вы можете определить свой геттер только извлечь словарь из архива, если у вас нет словаря:

    - (NSDictionary *)myDictionary { 
        if (!_myDictionary) { 
         NSString *path = [self pathToDataStore]; 
         if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { 
          _myDictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; 
         } 
        } 
    
        return _myDictionary; 
    } 
    
  3. Примечание, потому что вы определили как методы доступа, вы можете иметь @synthesize линию, которая явным образом определяет Ивар, что следует типичному подчеркивание конвенции: (?, кто владеет этим объектом, если не в этом классе)

    @synthesize myDictionary = _myDictionary; 
    
  4. Кроме того, использование спецификатора weak памяти любознательно. Я предлагаю сделать это strong.

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

  • Нет связанных вопросов^_^