Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.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
Cocoa 将SecIdentityRef存储到NSUserDefaults中_Cocoa_Openssl_Nsuserdefaults_Apple Push Notifications - Fatal编程技术网

Cocoa 将SecIdentityRef存储到NSUserDefaults中

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

我发现了一个很棒的解释,可以将APNS与可可一起使用。 现在我不想每次都选择SecIdentityRef(因为我很懒),我尝试将SecIdentityRef放入NSData并保存为默认值。下一次应用程序启动时,我会再次加载它,它总是获得exc\u bad\u访问权限。以下是我添加的代码:

// 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
    ,因此您必须将其存储为长而不透明的数据块,而不是字符串;忘记手动编辑此设置
  • 我在我的PDF签名应用程序中就是这样做的,到目前为止,它工作得完美无缺。以下是守则的相关部分:

    //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
    ,因此您必须将其存储为长而不透明的数据块,而不是字符串;忘记手动编辑此设置
  • 我在我的PDF签名应用程序中就是这样做的,到目前为止,它工作得完美无缺。以下是守则的相关部分:

    //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