无法从Swift字典检索CGColor [英] Trouble retrieving a CGColor from a Swift dictionary

查看:218
本文介绍了无法从Swift字典检索CGColor的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个可以存储任何对象的Swift字典.其中一些值将是CGColor引用.创建字典并存储CGColor引用没有问题.问题是试图安全地将它们找回.

I need a Swift dictionary that can store any kind of object. Some of the values will be CGColor references. I have no issue creating the dictionary and storing the CGColor references. The problem is trying to safely get them back.

let color = CGColor(gray: 0.5, alpha: 1)
var things = [String:Any]()
things["color"] = color
things["date"] = Date()
print(things)

那行得通,我得到了合理的输出.稍后我希望获得颜色(字典中可能存在或可能不存在.因此,我自然尝试以下操作:

That works and I get reasonable output. Later on I wish to get the color (which may or may not exist in the dictionary. So naturally I try the following:

if let color = things["color"] as? CGColor {
    print(color)
}

但这会导致错误:

错误:对CoreFoundation类型"CGColor"的条件向下转换将始终成功

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行上得到了警告:

This works without any warnings in a playground but in my actual Xcode project I get a warning on the if val is CGColor line:

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

'is' test always true because 'CGColor' is a Core Foundation type

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

Is there good solution to this problem?

我正在使用核心图形和图层,并且代码需要在iOS和macOS上都可以使用,因此我试图避免使用UIColorNSColor.

I'm working with core graphics and layers and the code needs to work with both iOS and macOS so I'm trying to avoid UIColor and NSColor.

我确实找到了从AnyObject投射到CGColor?没有错误或警告,这是相关的,但似乎不再相关,因为我不需要括号来消除警告,而且我正在尝试使用该问题未涵盖的可选绑定./p>

I did find Casting from AnyObject to CGColor? without errors or warnings which is related but doesn't seem relevant any more since I don't need the parentheses to eliminate the warning plus I'm trying to use optional binding which isn't covered by that question.

推荐答案

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

The problem is that Core Foundation objects are opaque, therefore a value of type CGColor is nothing more than an opaque pointer – Swift itself currently doesn't know anything about the underlying object. This therefore means that you cannot currently use is or as? to conditionally cast with it, Swift has to always allow the given cast to succeed (this will hopefully change in the future though – ideally the Swift runtime would use CFGetTypeID to check the type of the opaque pointer).

一种解决方案如Martin 用于使用 CFGetTypeID 为了检查Core Foundation对象的类型-为了方便起见,我建议将其分解为一个函数:

One solution, as shown by Martin in this Q&A, is to use CFGetTypeID in order to check the type of the Core Foundation object – which, I would recommend factoring out into a function for convenience:

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类型:

And you could even generalise this to other Core Foundation types with a protocol:

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字典检索CGColor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆