1

ココアでAPNSを使用するための素晴らしい解釈を見つけました。APNSプッシャー 今、私は毎回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])];
}

どうすればこれを機能させることができますか?IDを保存する別の方法はありますか?

編集

だから私はIDの名前を保存することで解決策を見つけました。アプリを起動すると、利用可能なIDのどれがこの名前を持っているかを調べ、正しい名前のIDを使用します。コードは次のとおりです。

//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. ID を保持することはできず、証明書のみを保持するため、2 つの間で変換するには追加のホップを通過する必要があります。
  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 に答える