【问题标题】:Translate just 4 lines of code from objective c to swift (Pointers)只需将 4 行代码从目标 c 转换为 swift(指针)
【发布时间】:2014-06-08 21:32:17
【问题描述】:

自从将一段代码从 Objective-C 翻译成 Swift 以来,我一直被困住了两天:

CFArrayRef keyref = NULL;
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(keyref, 0);
SecIdentityRef identityRef = (SecIdentityRef)CFDictionaryGetValue(identityDict,      kSecImportItemIdentity);

是的,就是这样!我根本无法用这些指针满足编译器。 请帮忙:-)

这是要翻译的整个目标 c 代码:

// Read .p12 file
NSString *path = [[NSBundle mainBundle] pathForResource:@"SSLKeyStoreClient" ofType:@"p12"];
NSData *pkcs12data = [[NSData alloc] initWithContentsOfFile:path];

// Import .p12 data
CFArrayRef keyref = NULL;
OSStatus sanityChesk = SecPKCS12Import((__bridge CFDataRef)pkcs12data,
                                       (__bridge CFDictionaryRef)[NSDictionary
                                                                  dictionaryWithObject:@"wed-zzz"
                                                                  forKey:(__bridge id)kSecImportExportPassphrase],
                                       &keyref);
if (sanityChesk != noErr) {
    NSLog(@"Error while importing pkcs12 [%d]", (int)sanityChesk);
} else
    NSLog(@"Success opening p12 certificate.");

// Identity
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(keyref, 0);
SecIdentityRef identityRef = (SecIdentityRef)CFDictionaryGetValue(identityDict,
                                                                  kSecImportItemIdentity);

// Cert
SecCertificateRef cert = NULL;
OSStatus status = SecIdentityCopyCertificate(identityRef, &cert);
if (status)
    NSLog(@"SecIdentityCopyCertificate failed.");

// the certificates array, containing the identity then the root certificate
NSArray *myCerts = [[NSArray alloc] initWithObjects:(__bridge id)identityRef, (__bridge id)cert, nil];

NSMutableDictionary *SSLOptions;
[SSLOptions setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsExpiredRoots];

NSDictionary *settings = [[NSDictionary alloc] initWithObjectsAndKeys:
                          [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
                          [NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot,
                          [NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
                          kCFNull,kCFStreamSSLPeerName,
                          myCerts,kCFStreamSSLCertificates,
                          nil];


CFReadStreamSetProperty((CFReadStreamRef)self.inputStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);
CFWriteStreamSetProperty((CFWriteStreamRef)self.outputStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);

这就是我目前得到的:

// Read .p12 file
var path = NSBundle.mainBundle().pathForResource("SSLKeyStoreClient", ofType: "p12")
var pkcs12data: NSData = NSData.dataWithContentsOfFile(path, options: nil, error: nil)

// Import .p12 data
var keyref: Unmanaged<CFArray>?


var optionDict: NSMutableDictionary = NSMutableDictionary()
optionDict.setValue("wed-zzz", forKey: kSecImportExportPassphrase!.takeRetainedValue())

var sanityChesk = SecPKCS12Import(pkcs12data,optionDict,&keyref)
if sanityChesk != 0{ //noErr
   println("Error while importing pkcs12 \(sanityChesk)")
} else {
   println("Success opening p12 certificate.")
}


// Identity
var key = keyref!
var identityDict: CFDictionary = CFArrayGetValueAtIndex(keyref, 0)
var identityRef:COpaquePointer = CFDictionaryGetValue(identityDict,nil)


// Cert
var cert: Unmanaged<SecCertificate>?
var status: OSStatus  = SecIdentityCopyCertificate(identityRef, &cert)
if status == 0{
    println("SecIdentityCopyCertificate failed.")
}

// the certificates array, containing the identity then the root certificate
var sslOptions = Dictionary<NSObject, NSObject>()

sslOptions[kCFStreamSSLAllowsExpiredRoots] = NSNumber.numberWithBool(true)

var settings = Dictionary<NSObject, NSObject>()
settings[kCFStreamSSLAllowsExpiredCertificates] = NSNumber.numberWithBool(true)
settings[kCFStreamSSLAllowsAnyRoot] = NSNumber.numberWithBool(true)
settings[kCFStreamSSLValidatesCertificateChain] = NSNumber.numberWithBool(false)
settings[kCFStreamSSLPeerName] = kCFNull
//settings[kCFStreamSSLCertificates] = myCerts



    CFReadStreamSetProperty(self.inputStream, kCFStreamPropertySSLSettings, settings)
    CFReadStreamSetProperty(self.inputStream, kCFStreamPropertySSLSettings, settings)

问题开始于:

var identityDict: CFDictionary = CFArrayGetValueAtIndex(keyref, 0)

错误:“非托管 CFArray 无法转换为 CFArray”。

这是我迄今为止最好的尝试。

【问题讨论】:

  • No [ ] 表示它不是 Objective-C。 ;) 请发布您尝试过的代码。 (或者至少这两天你尝试过的一些东西)
  • keyref 的真正价值是多少?显然它实际上不是 NULL。
  • 这是 C 代码,没有 ObjC 代码
  • @user3211074 对此有何更新?你有工作代码示例要分享吗?
  • 我确实有一个相关的问题。我正在为我的 SSL Connection mit Certificate Pinning 使用类似的代码片段。不幸的是,.p12 文件需要我的私钥才能在“keyref”数组中至少包含一个元素。 .p12 导入中没有私钥可以正常工作,但“keyref”中没有对象。由于密钥文件是应用程序的一部分并分发到商店,我不想包含私钥。我该如何处理这个问题?

标签: ios objective-c pointers swift


【解决方案1】:

大概第一行是实际数组的占位符?如果您实际上使用的是 NULL 数组指针,那么您的其余代码将什么也不做。

假设您从真正的 CFArrayRef 开始,您可以利用桥接:CoreFoundation 类型会自动像 Swift 对象一样处理,因此您不需要使用 CFArrayRefCFDictionaryRef 指针。任何其他使用 CF 类型系统的 C API 也是如此,因此它也应该适用于 SecIdentity

CF 集合的自动桥接似乎有些奇怪——你可以隐式地将 CFArray 桥接到 NSArrayNSArray 到 Swift Array&lt;T&gt;,你不能只下标 @987654330 @。

所以你的转换看起来像这样(包装在一个处理你假设的数组的函数中):

func getIdentity(keychainArray: NSArray) -> SecIdentity? {
    let dict = keychainArray[0] as Dictionary<String,AnyObject>
    let key = kSecImportItemIdentity.takeRetainedValue()
    return dict[key] as SecIdentity?
}

如果你有一个CFArray,你可以将它传递给这个函数,它会自动桥接/转换为NSArray,然后它会自动转换为一个 Swift 数组进行下标。将 item 0 视为 Swift 字典,您可以为字典下标以获取标识。对于密钥,您需要将其从 Unmanaged&lt;CFString&gt; 中提取出来,因为安全框架并未设置为隐式桥接该常量的声明。

我让这个函数返回一个可选的,因为我不知道你传入的数组+字典是否实际上包含一个标识。如果你确定是这样,你可以去掉两个问号。

(这在操场上编译,但我没有包含字典的数组,其中包含便于测试的身份,所以 caveat emptor。)

【讨论】:

  • 谢谢您,我已将您的提示用于类型转换。但是现在我遇到了另一个问题(我昨天不知何故已经存在)编译器错误:体系结构 i386 的未定义符号:“OBJC_CLASS_$_SecIdentity”,引用自:__TFC9messenger10Connection11getIdentityfS0_FCSo7NSArrayGSqCSo11SecIdentity in Connection.o ld:符号(s ) 未找到架构 i386 clang:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
  • 它似乎在操场上编译,但不是在空项目中。你有什么想法吗?
  • 我猜应该是测试版的问题,无法解释自己
  • 您的代码无法在正常项目中编译。仍然有上述错误。有什么想法吗?
  • 我已经修改了您的代码,现在可以编译,但是它以运行时错误结束。也许你可以帮我解决这个问题:let dict = keychainArray[0] as Dictionary&lt;NSString,SecIdentity&gt; let key:NSString = kSecImportItemIdentity.takeRetainedValue() return dict[key]! 结尾是:“致命错误:值无法从 Objective-C 类型桥接到 Swift 类型” 看来 SecIdentity 是 Swift 类型?!但是 Objective C 类型在哪里呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-26
  • 1970-01-01
  • 2018-04-08
  • 1970-01-01
相关资源
最近更新 更多