繁体   English   中英

无法从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)
}

但这会导致错误:

错误:对CoreFoundation类型'CGColor'的条件下调将始终成功

最后我想到了:

if let val = things["color"] {
    if val is CGColor {
        let color = val as! CGColor
        print(color)
    }
}

这在操场上没有任何警告的情况下工作,但是在我的实际Xcode项目中, if val is CGColor行,我会收到警告:

'is'测试始终为true,因为'CGColor'是Core Foundation类型

有解决这个问题的好方法吗?

我正在使用核心图形和图层,并且代码需要同时在iOS和macOS上使用,因此我尝试避免使用UIColorNSColor

我确实发现了从AnyObject转换为CGColor吗? 没有相关的错误或警告 ,但似乎不再相关,因为我不需要括号来消除警告,而且我正在尝试使用该问题未涵盖的可选绑定。

问题在于Core Foundation对象是不透明的,因此CGColor类型的值CGColor是一个不透明的指针CGColor本身目前对底层对象一无所知。 因此,这意味着您当前无法使用isas? 为了有条件地进行CFGetTypeID转换,Swift必须始终允许给定的CFGetTypeID转换成功(不过,希望将来会有所改变–理想情况下,Swift运行时将使用CFGetTypeID来检查不透明指针的类型)。

如Martin此问答中 所示,一种解决方案是使用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")
}

对于Swift 3:

    if let val = things["color"], CFGetTypeID(val as CFTypeRef) == CGColor.typeID {
        let color = val as! CGColor
        print(color)
    }

您也可以简化它,并将UIColor而不是CGColor存储在Dictionary中-这将允许您将standard as? UIImage as? UIImage方法

其他答案很有趣,但我只会使用包装器。 如此代码所示,您可以分配给Any并使用isas?再次取回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
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM