Создание подклассов Formatter для принятия Swift Structs в Swift 3.2 и более поздних версиях
Мне нужно отформатировать в нескольких местах один и тот же фрагмент данных в удобочитаемом формате. Тем не менее, у меня есть несколько структур, которые представляют эту информацию по-разному. Чтобы избежать дублирования этого кода, у меня есть 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:)
функция) - Есть
Widget
бытьclass
наряду с тем, что соответствуетWidgetRepresentable
,
Эти последние 2 пункта заставляют меня задуматься, не является ли это проблемой с мостом Objective-C между NSFoundation
а также Foundation
в Свифте.
Есть ли проблема с моей методологией здесь, или это ошибка в Swift? Если это последнее, я отправлю радар.