我有这个方法
- (NSString *)bundleSeedID:(NSError **)error __attribute__((annotate("oclint:suppress"))) {
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
(__bridge NSString *)kSecClassGenericPassword, (__bridge NSString *)kSecClass,
BUNDLE_SEED_ID, kSecAttrAccount,
EMPTY_STRING, kSecAttrService,
(__bridge NSString *)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, (__bridge NSString *)kSecAttrAccessible,
(id)kCFBooleanTrue, kSecReturnAttributes,
nil];
CFDictionaryRef result = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
if (status == errSecItemNotFound) {
status = SecItemAdd((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
}
if (status != errSecSuccess) {
if (error) *error = [ErrorUtils bundleSeedErrorWithCode:(int)status];
return nil;
}
NSString *accessGroup = [(__bridge NSDictionary *)result objectForKey:(__bridge NSString *)kSecAttrAccessGroup];
NSArray *components = [accessGroup componentsSeparatedByString:@"."];
NSString *bundleSeedID = [[components objectEnumerator] nextObject];
CFRelease(result);
return bundleSeedID;
}我不明白为什么有时结果是空的。
注意:这段代码总是在主线程中执行,没有任何异步调用。
你能帮我理解一下为什么会发生这种事吗?这段代码只有在我打开应用程序时才会执行。
我知道我可以检查结果是否为null,然后我将不会使用CFRelease(结果);但是它不会发生这种情况。一旦应用程序崩溃,如果我再次打开它,一切都好。
提前感谢
发布于 2020-07-15 22:12:21
当设备被锁定时,您很可能在后台启动。当设备被锁定时,您无法访问密钥链中的某些受保护的数据;您应该在错误消息中看到这一点。
您确实是在将kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly传递给创建程序,您可能在创建密钥链项之后将kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly添加到应用程序中(或者在创建其他地方时不传递此内容)。
您的代码检查errSecItemNotFound,但如果我还记得是否正确地检测到此问题,则应该检查errSecDataNotAvailable。(还可以查看UIApplication的“`isProtectedDataAvailable”。)当然,在这种情况下,您不应该尝试创建一个项目;您只需要一种优雅的失败方式。
在第一次解锁之前被发射是相当罕见的,但这也是可能的,并且密钥链将不可用。例如,挂起的蓝牙连接可能导致这种情况。我不相信推送通知可以在这种状态下启动应用程序,但这是可能的。
在任何情况下,您都需要检查意外错误并处理nil值。
https://stackoverflow.com/questions/62924443
复制相似问题