Cocoa 将SecIdentityRef存储到NSUserDefaults中
我发现了一个很棒的解释,可以将APNS与可可一起使用。 现在我不想每次都选择SecIdentityRef(因为我很懒),我尝试将SecIdentityRef放入NSData并保存为默认值。下一次应用程序启动时,我会再次加载它,它总是获得exc\u bad\u访问权限。以下是我添加的代码:Cocoa 将SecIdentityRef存储到NSUserDefaults中,cocoa,openssl,nsuserdefaults,apple-push-notifications,Cocoa,Openssl,Nsuserdefaults,Apple Push Notifications,我发现了一个很棒的解释,可以将APNS与可可一起使用。 现在我不想每次都选择SecIdentityRef(因为我很懒),我尝试将SecIdentityRef放入NSData并保存为默认值。下一次应用程序启动时,我会再次加载它,它总是获得exc\u bad\u访问权限。以下是我添加的代码: // For saving NSData *secRefData = [NSData dataWithBytes:[SFChooseIdentityPanel sharedChooseIdentityPanel
// 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"];
这一切都搞砸了。
SecIdentityRef
是对内部对象的不透明引用。您将其视为指向该对象的指针,但它可能只是一个表或其他对象的索引
其次,您不知道内部对象的大小。您的sizeof
表达式产生的是指针的大小,而不是它所引用的对象。无法获取实际大小,因为类型是不透明的
最后,没有理由相信对象是“标量”数据,可以写入文件,然后读取并保持完整。很可能,该对象包含的内部指针在另一个进程的地址空间中没有意义。更不用说你还没有保存和恢复那些指针可能指向的任何东西。这一切都搞砸了。
SecIdentityRef
是对内部对象的不透明引用。您将其视为指向该对象的指针,但它可能只是一个表或其他对象的索引
其次,您不知道内部对象的大小。您的sizeof
表达式产生的是指针的大小,而不是它所引用的对象。无法获取实际大小,因为类型是不透明的
最后,没有理由相信对象是“标量”数据,可以写入文件,然后读取并保持完整。很可能,该对象包含的内部指针在另一个进程的地址空间中没有意义。更不用说您还没有保存和还原这些指针可能指向的任何对象。使用
SecKeychainItemCreatePersistentReference()
和SecKeychainItemCopyFromPersistentReference()
——它们可以在进程之间传递或持久化。不过,有一些警告:
NSData
,因此您必须将其存储为长而不透明的数据块,而不是字符串;忘记手动编辑此设置//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"];
-(NSData*)标识持久化:(SecIdentityRef)标识
{
骨状态;
安全证书;
CFDataRef data=nil;
状态=SecIdentityCopyCertificate(ident和cert);
如果(状态!=noErr)
返回零;
状态=SecKeychainItemCreatePersistentReference((SecKeychainItemRef)证书和数据);
CFRelease(cert);
如果(状态!=noErr)
返回零;
返回发布(数据);
}
-(SecIdentityRef)持久:(NSData*)数据的标识
{
骨状态;
SecKeychainItemRef证书;
SecIdentityRef ident=nil;
状态=SecKeychainItemCopyFromPersistentReference((u桥CFDataRef)数据和证书);
如果(状态!=noErr)
返回零;
状态=SecIdentityCreateWithCertificate(NULL,(SecCertificateRef)cert,&ident);
CFRelease(cert);
返回标识;
}
-(SecIdentityRef)获取首选身份
{
NSData*数据=[[NSUserDefaults standardUserDefaults]dataForKey:@“SigningIdentity”];
如果(!数据)
返回零;
返回[self identityfrompsistent:data];
}
-(void)setPreferredIdentity:(SecIdentityRef)ident
{
NSData*数据=[self identityToPersistent:ident];
[[NSUserDefaults standardUserDefaults]设置对象:数据分叉:@“SigningIdentity”];
}
使用SecKeychainItemCreatePersistentReference()
和SecKeychainItemCopyFromPersistentReference()
——它们可以在进程之间传递或持久化。不过,有一些警告:
NSData
,因此您必须将其存储为长而不透明的数据块,而不是字符串;忘记手动编辑此设置//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"];
-(NSData*)标识持久化:(SecIdentityRef)标识
{
骨状态;
安全证书;
CFDataRef data=nil;
状态=SecIdentityCopyCertificate(ident和cert);
如果(状态!=noErr)
返回零;
状态=SecKeychainItemCreatePersistentReference((SecKeychainItemRef)证书和数据);
CFRelease(cert);
如果(状态!=noErr)
返回零;
返回发布(数据);
}
-(SecIdentityRef)持久:(NSData*)数据的标识
{
骨状态;
SecKeychainItemRef证书;
SecIdentityRef ident=nil;
状态=SecKeychainItemCopyFromPersistentReference((u桥CFDataRef)数据和证书);
如果(状态!=noErr)
返回零;
状态=SecIdentityCreateWithCertificate(NULL,(SecCertificateRef)cert,&ident);
CFRelease(cert);
返回标识;
}
-(SecIdentityRef)获取首选身份
{
NSData*数据=[[NSUserDefaults standardUserDefaults]dataForKey:@“SigningIdentity”];
如果(!数据)
返回零;
返回[self identityfrompsistent:data];
}
-(void)setPreferredIdentity:(SecIdentityRef)ident
{
NSData*数据=[self identityToPersistent:ident];
[[NSUserDefault