2015-10-21 4 views
-1

У меня есть класс, который сохраняет NSDictionary в KeyChain. Он работал нормально, но внезапно, когда я пытаюсь загрузить NSDictionary, я получаю нулевое значение.Брелок возвращает разные значения при каждом вызове

Это класс:

// 
// KeyChainHandler.m 
// 
// 

#import "KeyChainHandler.h" 

#define IDENTIFIER @"Identifier" 

@interface KeyChainHandler() 

@property (strong, nonatomic, readwrite) NSDictionary *applicationData; 

@end 

@implementation KeyChainHandler 

// Make this class a singleton 
static KeyChainHandler *instance = nil; 

+ (KeyChainHandler*)sharedKeyChain 
{ 
    @synchronized(self) 
    { 
     if (!instance) { 
      instance = [[self alloc] init]; 
     } 
    } 
    return instance; 
} 

- (id)init 
{ 
    self = [super init]; 
    if (self) 
    { 
     [self load]; 
    } 
    return self; 
} 

- (void)saveObject:(NSDictionary*)data 
{ 
    self.applicationData = data; 
    [self storeDictionary:data toKeychainWithKey:IDENTIFIER]; 
} 

- (NSDictionary*)load 
{ 
    NSDictionary *data = [KeyChainHandler dictionaryFromKeychainWithKey:IDENTIFIER]; 
    self.applicationData = data; 
    return data; 
} 

- (void)remove 
{ 
    [self deleteDictionaryFromKeychainWithKey:IDENTIFIER]; 
} 

- (void)storeDictionary:(NSDictionary*)data toKeychainWithKey:(NSString*)aKey 
{ 
    // serialize dict 
    NSData *serializedDictionary = [NSKeyedArchiver archivedDataWithRootObject:data]; 
    // encrypt in keychain 
    // first, delete potential existing entries with this key (it won't auto update) 
    [self remove]; 

    // setup keychain storage properties 
    NSDictionary *storageQuery = @{ 
            (__bridge id)kSecAttrAccount: aKey, 
            (__bridge id)kSecValueData:  serializedDictionary, 
            (__bridge id)kSecClass:   (__bridge id)kSecClassGenericPassword, 
            (__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleWhenUnlocked 
            }; 
    OSStatus osStatus = SecItemAdd((__bridge CFDictionaryRef)storageQuery, nil); 
    if(osStatus != noErr) { 
     // do someting with error 
    } 
} 


+ (NSDictionary*)dictionaryFromKeychainWithKey:(NSString *)aKey 
{ 
    // setup keychain query properties 
    NSDictionary *readQuery = @{ 
           (__bridge id)kSecAttrAccount: aKey, 
           (__bridge id)kSecReturnData: (id)kCFBooleanTrue, 
           (__bridge id)kSecClass:  (__bridge id)kSecClassGenericPassword 
           }; 

    CFDataRef serializedDictionary = NULL; 
    OSStatus osStatus = SecItemCopyMatching((__bridge CFDictionaryRef)readQuery, (CFTypeRef *)&serializedDictionary); 
    if(osStatus == noErr) { 
     // deserialize dictionary 
     NSData *data = (__bridge NSData *)serializedDictionary; 
     NSDictionary *storedDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 
     return storedDictionary; 
    } 
    else { 
     // do something with error 
     return nil; 
    } 
} 


- (void)deleteDictionaryFromKeychainWithKey:(NSString*)aKey 
{ 
    // setup keychain query properties 
    NSDictionary *deletableItemsQuery = @{ 
              (__bridge id)kSecAttrAccount:  aKey, 
              (__bridge id)kSecClass:    (__bridge id)kSecClassGenericPassword, 
              (__bridge id)kSecMatchLimit:   (__bridge id)kSecMatchLimitAll, 
              (__bridge id)kSecReturnAttributes: (id)kCFBooleanTrue 
              }; 

    CFArrayRef itemList = nil; 
    OSStatus osStatus = SecItemCopyMatching((__bridge CFDictionaryRef)deletableItemsQuery, (CFTypeRef *)&itemList); 
    // each item in the array is a dictionary 
    NSArray *itemListArray = (__bridge NSArray *)itemList; 
    for (NSDictionary *item in itemListArray) { 
     NSMutableDictionary *deleteQuery = [item mutableCopy]; 
     [deleteQuery setValue:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; 
     // do delete 
     osStatus = SecItemDelete((__bridge CFDictionaryRef)deleteQuery); 
     if(osStatus != noErr) { 
      // do something with error 
     } 
    } 
} 

@end 

В AppDelegate когда я печатаю [[KeyChainHandler sharedHandler] load]; я получить правильные данные, то на экране входа в систему, я стараюсь делать это снова и я получаю nil. Затем, когда я перезапускаю (только с CMD + R) приложение, я не получаю nil, я снова получаю правильные данные.

В чем проблема? может быть, это какая-то ошибка Apple?

+0

Является ли ошибка на симуляторе или устройстве? Почему это Синглтон? Почему существует свойство 'applicationData', поскольку оно никогда не доступно, установлено только? – zaph

+0

Это устройство. Но в одном он работает, а другой - нет. к applicationData обращаются из другого класса. –

+0

Ах, @interface не в этом вопросе. – zaph

ответ

1

Почему: позвонить [[KeyChainHandler sharedHandler] load];, свойство уже загружено при создании одноэлементного ордера, и если изменено свойство, оно также будет обновлено.

Вам необходимо установить свойство nil в remove.

Вместо просто использовать:

NSDictionary *dict = [KeyChainHandler sharedKeyChain].applicationData; 

Примечания: код: sharedKeyChain, пример вызов: sharedHandler.