从 Swift 字典中检索 CGColor 时遇到问题
Trouble retrieving a CGColor from a Swift dictionary
我需要一个可以存储任何类型对象的 Swift 字典。一些值将是 CGColor
引用。创建字典和存储 CGColor
引用没有问题。问题是试图安全地让他们回来。
let color = CGColor(gray: 0.5, alpha: 1)
var things = [String:Any]()
things["color"] = color
things["date"] = Date()
print(things)
这行得通,我得到了合理的输出。稍后我希望获得颜色(字典中可能存在也可能不存在。所以我自然会尝试以下操作:
if let color = things["color"] as? CGColor {
print(color)
}
但这会导致错误:
error: conditional downcast to CoreFoundation type 'CGColor' will always succeed
最后我想出了:
if let val = things["color"] {
if val is CGColor {
let color = val as! CGColor
print(color)
}
}
这在操场上没有任何警告,但在我的实际 Xcode 项目中,我在 if val is CGColor
行收到警告:
'is' test always true because 'CGColor' is a Core Foundation type
这个问题有好的解决办法吗?
我正在处理核心图形和图层,代码需要同时适用于 iOS 和 macOS,因此我试图避免使用 UIColor
和 NSColor
。
我确实找到了 ,它是相关的,但似乎不再相关,因为我不需要括号来消除警告,而且我正在尝试使用未涵盖的可选绑定通过那个问题。
对于Swift 3:
if let val = things["color"], CFGetTypeID(val as CFTypeRef) == CGColor.typeID {
let color = val as! CGColor
print(color)
}
您也可以保持简单,将 UIColor
存储在您的字典中而不是 CGColor - 这将允许您使用标准 as? UIImage
方法
问题在于 Core Foundation 对象是不透明的,因此 CGColor
类型的值只不过是一个不透明的指针 – Swift 本身目前对底层对象一无所知。因此,这意味着您目前不能使用 is
或 as?
来有条件地使用它进行投射,Swift 必须始终允许给定的投射成功(不过这有望在未来改变——理想情况下) Swift 运行时将使用 CFGetTypeID
检查不透明指针的类型)。
一个解决方案, in , is to use CFGetTypeID
以检查 Core Foundation 对象的类型——为了方便,我建议将其分解为一个函数:
func maybeCast<T>(_ value: T, to cfType: CGColor.Type) -> CGColor? {
guard CFGetTypeID(value as CFTypeRef) == cfType.typeID else {
return nil
}
return (value as! CGColor)
}
// ...
if let color = maybeCast(things["color"], to: CGColor.self) {
print(color)
} else {
print("nil, or not a color")
}
您甚至可以使用协议将其推广到其他 Core Foundation 类型:
protocol CFTypeProtocol {
static var typeID: CFTypeID { get }
}
func maybeCast<T, U : CFTypeProtocol>(_ value: T, to cfType: U.Type) -> U? {
guard CFGetTypeID(value as CFTypeRef) == cfType.typeID else {
return nil
}
return (value as! U)
}
extension CGColor : CFTypeProtocol {}
extension CGPath : CFTypeProtocol {}
// Some CF types don't have their ID imported as the 'typeID' static member,
// you have to implement it yourself by forwarding to their global function.
extension CFDictionary : CFTypeProtocol {
static var typeID: CFTypeID { return CFDictionaryGetTypeID() }
}
// ...
let x: Any? = ["hello": "hi"] as CFDictionary
if let dict = maybeCast(x, to: CFDictionary.self) {
print(dict)
} else {
print("nil, or not a dict")
}
其他答案很有趣,但我只想使用包装器。如这段代码所示,您可以分配给 Any 并使用 is
或 as?
测试再次取回它:
struct ColorWrapper {
let color:CGColor
}
let c = ColorWrapper(color:UIColor.red.cgColor)
let any : Any = c
if let c2 = any as? ColorWrapper {
let result = c2.color
}
我需要一个可以存储任何类型对象的 Swift 字典。一些值将是 CGColor
引用。创建字典和存储 CGColor
引用没有问题。问题是试图安全地让他们回来。
let color = CGColor(gray: 0.5, alpha: 1)
var things = [String:Any]()
things["color"] = color
things["date"] = Date()
print(things)
这行得通,我得到了合理的输出。稍后我希望获得颜色(字典中可能存在也可能不存在。所以我自然会尝试以下操作:
if let color = things["color"] as? CGColor {
print(color)
}
但这会导致错误:
error: conditional downcast to CoreFoundation type 'CGColor' will always succeed
最后我想出了:
if let val = things["color"] {
if val is CGColor {
let color = val as! CGColor
print(color)
}
}
这在操场上没有任何警告,但在我的实际 Xcode 项目中,我在 if val is CGColor
行收到警告:
'is' test always true because 'CGColor' is a Core Foundation type
这个问题有好的解决办法吗?
我正在处理核心图形和图层,代码需要同时适用于 iOS 和 macOS,因此我试图避免使用 UIColor
和 NSColor
。
我确实找到了
对于Swift 3:
if let val = things["color"], CFGetTypeID(val as CFTypeRef) == CGColor.typeID {
let color = val as! CGColor
print(color)
}
您也可以保持简单,将 UIColor
存储在您的字典中而不是 CGColor - 这将允许您使用标准 as? UIImage
方法
问题在于 Core Foundation 对象是不透明的,因此 CGColor
类型的值只不过是一个不透明的指针 – Swift 本身目前对底层对象一无所知。因此,这意味着您目前不能使用 is
或 as?
来有条件地使用它进行投射,Swift 必须始终允许给定的投射成功(不过这有望在未来改变——理想情况下) Swift 运行时将使用 CFGetTypeID
检查不透明指针的类型)。
一个解决方案,CFGetTypeID
以检查 Core Foundation 对象的类型——为了方便,我建议将其分解为一个函数:
func maybeCast<T>(_ value: T, to cfType: CGColor.Type) -> CGColor? {
guard CFGetTypeID(value as CFTypeRef) == cfType.typeID else {
return nil
}
return (value as! CGColor)
}
// ...
if let color = maybeCast(things["color"], to: CGColor.self) {
print(color)
} else {
print("nil, or not a color")
}
您甚至可以使用协议将其推广到其他 Core Foundation 类型:
protocol CFTypeProtocol {
static var typeID: CFTypeID { get }
}
func maybeCast<T, U : CFTypeProtocol>(_ value: T, to cfType: U.Type) -> U? {
guard CFGetTypeID(value as CFTypeRef) == cfType.typeID else {
return nil
}
return (value as! U)
}
extension CGColor : CFTypeProtocol {}
extension CGPath : CFTypeProtocol {}
// Some CF types don't have their ID imported as the 'typeID' static member,
// you have to implement it yourself by forwarding to their global function.
extension CFDictionary : CFTypeProtocol {
static var typeID: CFTypeID { return CFDictionaryGetTypeID() }
}
// ...
let x: Any? = ["hello": "hi"] as CFDictionary
if let dict = maybeCast(x, to: CFDictionary.self) {
print(dict)
} else {
print("nil, or not a dict")
}
其他答案很有趣,但我只想使用包装器。如这段代码所示,您可以分配给 Any 并使用 is
或 as?
测试再次取回它:
struct ColorWrapper {
let color:CGColor
}
let c = ColorWrapper(color:UIColor.red.cgColor)
let any : Any = c
if let c2 = any as? ColorWrapper {
let result = c2.color
}