协议与隐式解包选项的一致性

Protocol conformance with implicitly unwrapped optionals

我正在尝试制作一个 Swift 协议,我可以在 UILabelUITextFieldUITextView 上使用,其中包含他们的 textattributedTextfont 属性。

然而,不幸的是,这三个 类 与它们是否为这些属性使用可选类型或隐式展开可选类型不一致。

例如,如果我创建这个协议:

protocol MyProtocol: class {
    var font: UIFont? { get set }
}

然后我应用它:

extension UILabel: MyProtocol { }
extension UITextField: MyProtocol { }
extension UITextView: MyProtocol { }

它适用于 UITextFieldUITextViewUILabelfont 属性 是 UIFont! 所以编译器说 UILabel 不符合 MyProtocol.

此外 textattributedText 对于 UILabelUITextField 是可选的 (String?) 但对于 UITextView 隐式解包 (String!).因此,对于所有三个属性,哪些使用可选项,哪些使用隐式展开的可选项甚至不一致。

所以我不得不将协议中的 font 重命名为例如。 uiFont 本质上是 font 的别名,在上面的每个扩展中都有以下实现:

extension UILabel: MyProtocol {
    var uiFont: UIFont? {
        get { font }
        set { font = newValue }
    }
} 
// … and similarly for UITextField and UITextView

这有点烦人,因为它破坏了协议的简单性。

我找到了 this post on the Swift forum that seems to be the same issue and the discussion seems to say this is not how it's supposed to behave in Swift 4.2, but I am using Swift 5 and still getting this. There was even a proposal to abolish IUOs that got merged

注意我在 macOS Catalina 10.15.6 (19G2021) 上使用 Xcode 11.7 和 iOS 13.7。

有没有什么方法可以完全避免这个问题,或者可以让代码更简洁一些,这样我就不需要那么多冗余了?

谢谢

虽然它看起来像是 Swift 中的错误,但您可以扩展协议本身以使其工作:

extension UILabel: MyProtocol { }
extension MyProtocol where Self: UILabel {
    var font: UIFont? {
        get { self.font ?? nil }
        set { self.font = newValue }
    }
}