我需要在几个地方将同一条数据格式化为人类可读的格式。但是,我有几个框架以不同的方式表示这些信息。为避免重复此代码,我有一个Formatter
用于格式化此数据的通用表示的方法。任何想要使用这种人类可读表示的框架都可以让他们的数据声明符合一个Protocol
(通常在扩展中),将他们自己的表示转换Struct
为格式化程序使用的通用表示。
这正如我在 Swift 3 中所期望的那样工作。但是,在 Swift 3.2 及更高版本中,向Protocol
内部的强制转换string(for obj:)
失败。我不知道这是故意的改变,还是一个错误。在这个例子中:
import Foundation
struct Widget {
let frobberCount: Int
let tweakerCount: Int
}
protocol WidgetRepresentable {
var widgetRepresentation: Widget { get }
}
extension Widget: WidgetRepresentable {
var widgetRepresentation: Widget {
return self
}
}
class WidgetFormatter: Formatter {
override func string(for obj: Any?) -> String? {
guard let widget = obj as? WidgetRepresentable else { // This cast fails
return nil
}
return string(from: widget)
}
func string(from widgetRepresentable: WidgetRepresentable) -> String {
let widget = widgetRepresentable.widgetRepresentation
return "\(widget.frobberCount) frobber(s), \(widget.tweakerCount) tweaker(s)"
}
}
let formatter = WidgetFormatter()
let widget = Widget(frobberCount: 2, tweakerCount: 4)
formatter.string(for: widget) // Returns nil. Expected 2 frobber(s), 4 tweaker(s)
formatter.string(from: widget) // Correctly returns 2 frobber(s), 4 tweaker(s)
作为一种解决方法,如果我执行以下任何操作,问题就会消失:
- 使用便利
string(from:)
功能,而不是string(for:)
从Formatter
. WidgetFormatter
不再有子类(从函数中Formatter
删除override
注释)string(for:)
- Have
Widget
be aclass
,以及任何符合 的WidgetRepresentable
。
最后两点让我想知道这是否是Swift之间NSFoundation
的Objective-C 桥接问题。Foundation
我的方法是否存在问题,或者这是 Swift 中的错误?如果是后者,我会归档雷达。