Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/100.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Keychain在每个调用中返回不同的值_Ios_Objective C_Keychain - Fatal编程技术网

Ios Keychain在每个调用中返回不同的值

Ios Keychain在每个调用中返回不同的值,ios,objective-c,keychain,Ios,Objective C,Keychain,我有一个类可以将NSDictionary保存到钥匙链中。它工作得很好,但是当我尝试加载NSDictionary时,突然得到了nil值 这是一节课: // // KeyChainHandler.m // // #import "KeyChainHandler.h" #define IDENTIFIER @"Identifier" @interface KeyChainHandler () @property (strong, nonatomic, readwrite) NSDiction

我有一个类可以将
NSDictionary
保存到钥匙链中。它工作得很好,但是当我尝试加载
NSDictionary
时,突然得到了nil值

这是一节课:

//
//  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
当我打印
[[KeyChainHandler sharedHandler]load]时,在
AppDelegate
我得到了正确的数据,然后在登录屏幕上再次尝试,结果得到
nil
。然后,当我重新启动(仅使用CMD+R)应用程序时,我不会得到
nil
,我会再次得到正确的数据


有什么问题吗?也许这是某种苹果的bug?

为什么:调用
[[KeyChainHandler sharedHandler]load],该属性已在单例创建时加载,如果更改,该属性也将更新

您确实需要在
remove
中将属性设置为
nil

相反,只需使用:

NSDictionary *dict = [KeyChainHandler sharedKeyChain].applicationData;

注意:代码是:
sharedKeyChain
,示例调用是:
sharedHandler

是模拟器或设备上的错误吗?为什么这是单身?为什么会有属性
applicationData
,因为它从不被访问,只被设置?它在设备上。但一个有效,另一个无效。applicationData是从另一个类访问的。啊,@接口不是问题所在。这段代码看起来不错,但你不应该忽略错误——至少要将它们打印到控制台,看看是否有问题。我想你在别的地方会有问题的。也许您正在删除应用程序中的某个位置的密钥?此外,我认为您应该始终使用
kSecAttrService
,因为项目实际上是由
kSecAttrService
kSecAttrAccount
对标识的。