CFDictionary 不会桥接到 NSDictionary (Swift 2.0 / iOS9)
CFDictionary won't bridge to NSDictionary (Swift 2.0 / iOS9)
好的,这是我在使用 CGImageSource 时遇到的一个案例,我注意到 CFDictionary 和 NSDictionary 之间的免费桥接在某些情况下似乎 运行 会出现问题。我设法构建了以下示例来说明我的意思:
func optionalProblemDictionary() -> CFDictionary? {
let key = "key"
let value = "value"
var keyCallBacks = CFDictionaryKeyCallBacks()
var valueCallBacks = CFDictionaryValueCallBacks()
let cfDictionary = CFDictionaryCreate(kCFAllocatorDefault, UnsafeMutablePointer(unsafeAddressOf(key)), UnsafeMutablePointer(unsafeAddressOf(value)), 1, &keyCallBacks, &valueCallBacks)
return cfDictionary
}
相当简单(也有点傻),但它是一个函数返回和可选的 CFDictionary。 "fun" 在尝试从此函数创建 NSDictionary 时启动:
为什么下面的方法不起作用?
if let problemDictionary = optionalProblemDictionary() as? NSDictionary {
print(problemDictionary) // never enters, no warnings, compiles just fine
}
虽然这很好用?
if let cfDictionary = optionalProblemDictionary() {
let problemDictionary = cfDictionary as NSDictionary
print(problemDictionary)
}
XCode 7.0 (7A220)
原因似乎是函数 returns 一个 optional
CFDictionary?
并且不能转换为(非可选)
NSDictionary
.
这是一个更简单的示例,展示了 CFString
与 NSString
的相同问题:
let cfString = "foobar" as CFString?
if let s1 = cfString as? NSString {
print("s1 = \(s1)") // not executed
}
(问题仍然是为什么这不会给出编译器错误或
至少是一个编译器警告,因为这个可选的转换可以
从未成功。)
但是转换为可选的 NSString?
是可行的:
if let s2 = cfString as NSString? {
print("s2 = \(s2)") // prints "s2 = foobar"
}
在您的情况下,如果将 "problematic case" 更改为
if let problemDictionary = cfDict as NSDictionary? {
print(problemDictionary)
}
然后执行 if 块。
请注意,您在 Swift 中构建 CFDictionary
的方法不正确
实际上在我的测试中导致了程序崩溃。一个原因是
字典回调设置为空结构。
另一个问题是 unsafeAddressOf(key)
桥接 Swift
字符串到可以立即释放的 NSString
。
我不知道在 Swift 中构建 CFDictionary
的最佳方法是什么,
但这在我的测试中有效:
func optionalProblemDictionary() -> CFDictionary? {
let key = "key" as NSString
let value = "value" as NSString
var keys = [ unsafeAddressOf(key) ]
var values = [ unsafeAddressOf(value) ]
var keyCallBacks = kCFTypeDictionaryKeyCallBacks
var valueCallBacks = kCFTypeDictionaryValueCallBacks
let cfDictionary = CFDictionaryCreate(kCFAllocatorDefault, &keys, &values, 1, &keyCallBacks, &valueCallBacks)
return cfDictionary
}
好的,这是我在使用 CGImageSource 时遇到的一个案例,我注意到 CFDictionary 和 NSDictionary 之间的免费桥接在某些情况下似乎 运行 会出现问题。我设法构建了以下示例来说明我的意思:
func optionalProblemDictionary() -> CFDictionary? {
let key = "key"
let value = "value"
var keyCallBacks = CFDictionaryKeyCallBacks()
var valueCallBacks = CFDictionaryValueCallBacks()
let cfDictionary = CFDictionaryCreate(kCFAllocatorDefault, UnsafeMutablePointer(unsafeAddressOf(key)), UnsafeMutablePointer(unsafeAddressOf(value)), 1, &keyCallBacks, &valueCallBacks)
return cfDictionary
}
相当简单(也有点傻),但它是一个函数返回和可选的 CFDictionary。 "fun" 在尝试从此函数创建 NSDictionary 时启动:
为什么下面的方法不起作用?
if let problemDictionary = optionalProblemDictionary() as? NSDictionary {
print(problemDictionary) // never enters, no warnings, compiles just fine
}
虽然这很好用?
if let cfDictionary = optionalProblemDictionary() {
let problemDictionary = cfDictionary as NSDictionary
print(problemDictionary)
}
XCode 7.0 (7A220)
原因似乎是函数 returns 一个 optional
CFDictionary?
并且不能转换为(非可选)
NSDictionary
.
这是一个更简单的示例,展示了 CFString
与 NSString
的相同问题:
let cfString = "foobar" as CFString?
if let s1 = cfString as? NSString {
print("s1 = \(s1)") // not executed
}
(问题仍然是为什么这不会给出编译器错误或 至少是一个编译器警告,因为这个可选的转换可以 从未成功。)
但是转换为可选的 NSString?
是可行的:
if let s2 = cfString as NSString? {
print("s2 = \(s2)") // prints "s2 = foobar"
}
在您的情况下,如果将 "problematic case" 更改为
if let problemDictionary = cfDict as NSDictionary? {
print(problemDictionary)
}
然后执行 if 块。
请注意,您在 Swift 中构建 CFDictionary
的方法不正确
实际上在我的测试中导致了程序崩溃。一个原因是
字典回调设置为空结构。
另一个问题是 unsafeAddressOf(key)
桥接 Swift
字符串到可以立即释放的 NSString
。
我不知道在 Swift 中构建 CFDictionary
的最佳方法是什么,
但这在我的测试中有效:
func optionalProblemDictionary() -> CFDictionary? {
let key = "key" as NSString
let value = "value" as NSString
var keys = [ unsafeAddressOf(key) ]
var values = [ unsafeAddressOf(value) ]
var keyCallBacks = kCFTypeDictionaryKeyCallBacks
var valueCallBacks = kCFTypeDictionaryValueCallBacks
let cfDictionary = CFDictionaryCreate(kCFAllocatorDefault, &keys, &values, 1, &keyCallBacks, &valueCallBacks)
return cfDictionary
}