1

我发现了将 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"];
4

2 回答 2

1

使用SecKeychainItemCreatePersistentReference()and SecKeychainItemCopyFromPersistentReference()-- 它们可以在进程之间传递或持久化。不过,有一些警告:

  1. 您不能保留身份,只能保留证书,因此您必须通过额外的跃点才能在两者之间进行转换。
  2. 您将获得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"];
}
于 2013-05-06T12:07:28.657 回答
0

这一切都搞砸了。ASecIdentityRef是对内部对象的不透明引用。您将其视为指向该对象的指针,但它可能只是表的索引或其他任何内容。

其次,你不知道内部对象的大小。您的sizeof表达式正在产生指针的大小,而不是它所指的对象。由于类型是不透明的,因此无法获得实际大小。

最后,没有理由相信该对象是“标量”数据,它被写入文件然后被读出并保持不变。很可能,该对象包含在另一个进程的地址空间中没有意义的内部指针。更不用说您还没有保存和恢复这些指针可能指向的任何内容。

于 2012-04-13T12:08:39.777 回答