我发现使用APNS和可可的一个很棒的解释。 APNS Pusher 现在我不想每次都选择我的SecIdentityRef(因为我很懒)我尝试将SecIdentityRef放入NSData并将其保存为默认值。下次应用程序启动时我再次加载它,它总是得到exc_bad_access。这是我添加的代码:
// For saving
NSData *secRefData = [NSData dataWithBytes:[SFChooseIdentityPanel sharedChooseIdentityPanel].identity length:sizeof([SFChooseIdentityPanel sharedChooseIdentityPanel].identity)];
[[NSUserDefaults standardUserDefaults] setValue:secRefData forKey:@"identity"];
//For loading
NSData *secRefData = [[NSUserDefaults standardUserDefaults] valueForKey:@"identity"];
if([secRefData length] != 0) {
[[APNS sharedAPNS] setIdentity:(SecIdentityRef)CFRetain([secRefData bytes])];
}
我怎样才能让它发挥作用?我还有另一种存储身份的方式吗?
修改
所以我通过保存身份名称找到了解决方案,在启动应用程序时,它会查看哪些可用身份具有此名称并使用具有正确名称的身份。这是代码:
//For loading
NSString *lastIdentityName = [[NSUserDefaults standardUserDefaults] valueForKey:@"identityName"];
if([lastIdentityName length] != 0) {
NSArray *allIdentities = [self identities];
for (id object in allIdentities) {
NSString *theName = [[[X509Certificate extractCertDictFromIdentity:(SecIdentityRef)object] valueForKey:@"Subject"] objectForKey:@"CommonName"];
if([theName isEqualToString:lastIdentityName]) {
[[APNS sharedAPNS] setIdentity:(SecIdentityRef)CFRetain((__bridge_retained SecIdentityRef)object)];
[[NSUserDefaults standardUserDefaults] setValue:[self identityName] forKey:@"identityName"];
// KVO trigger
[self willChangeValueForKey:@"identityName"];
[self didChangeValueForKey:@"identityName"];
}
}
}
//For saving
[[NSUserDefaults standardUserDefaults] setValue:[self identityName] forKey:@"identityName"];
答案 0 :(得分:1)
使用SecKeychainItemCreatePersistentReference()
和SecKeychainItemCopyFromPersistentReference()
- 它们可以在进程之间传递或持久化。但是有一些警告:
NSData
长而不透明的数据块,所以你必须将它存储起来,而不是像作为一个字符串;并且忘记了能够手动编辑此设置。这就是我在我的PDF签名应用程序中的表现方式,到目前为止它完美无瑕。以下是代码的相关部分:
- (NSData*) identityToPersistent:(SecIdentityRef)ident
{
OSStatus status;
SecCertificateRef cert;
CFDataRef data = nil;
status = SecIdentityCopyCertificate(ident, &cert);
if (status != noErr)
return nil;
status = SecKeychainItemCreatePersistentReference((SecKeychainItemRef)cert, &data);
CFRelease(cert);
if (status != noErr)
return nil;
return CFBridgingRelease(data);
}
- (SecIdentityRef) identityFromPersistent:(NSData*)data
{
OSStatus status;
SecKeychainItemRef cert;
SecIdentityRef ident = nil;
status = SecKeychainItemCopyFromPersistentReference((__bridge CFDataRef)data, &cert);
if (status != noErr)
return nil;
status = SecIdentityCreateWithCertificate(NULL, (SecCertificateRef)cert, &ident);
CFRelease(cert);
return ident;
}
- (SecIdentityRef) getPreferredIdentity
{
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:@"SigningIdentity"];
if (!data)
return nil;
return [self identityFromPersistent:data];
}
- (void) setPreferredIdentity:(SecIdentityRef)ident
{
NSData *data = [self identityToPersistent:ident];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"SigningIdentity"];
}
答案 1 :(得分:0)
这一切都搞砸了。 SecIdentityRef
是对内部对象的不透明引用。你把它看作是指向那个对象的指针,但它可能只是一个表或其他什么的索引。
其次,您不知道内部对象的大小。您的sizeof
表达式产生指针的大小,而不是它引用的对象。没有办法获得实际尺寸,因为类型是不透明的。
最后,没有理由相信该对象是写入文件然后读出并保持完整的“标量”数据。很可能,该对象包含内部指针,这些指针在另一个进程的地址空间中没有意义。更不用说你没有保存和恢复那些指针可能指向的事实。