【问题标题】:Protocol conformance with implicitly unwrapped optionals与隐式解包选项的协议一致性
【发布时间】:2020-09-03 23:10:07
【问题描述】:

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

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

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

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

我应用它:

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

它对UITextFieldUITextView 工作正常,但UILabelfont 属性是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 似乎是同一个问题,讨论似乎说这不是它在 Swift 4.2 中应该表现的方式,但我正在使用 Swift 5 并且仍然得到这个。甚至还有一个proposal to abolish IUOs 得到了merged

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

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

谢谢

【问题讨论】:

  • 优秀的总结。我建议提交一个错误。我们总是被告知隐式展开的 Optional 只是“是”一个 Optional 那么为什么它会像这样妨碍你呢? (而且为什么 API 中还剩下任何 IUO?
  • 猜猜这不是一个真正的错误(请参阅上面 swift.org 上的错误)。

标签: ios swift uilabel swift-protocols swift-optionals


【解决方案1】:

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

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

【讨论】:

  • 太棒了!这大大减少了解决方法代码,因为现在我只需要为UILabelUITextView 添加扩展名。没有意识到您可以在没有循环引用的情况下使用相同的属性名称。
  • 正如 Swift 错误跟踪器上的评论者指出的那样,这对可读性/调试有点不利。当您在隐含为UILabelUILabel 的显式实例的MyProtocol 实例上调用font 时,尚不清楚您是在访问font 的别名还是实际属性。在这种情况下,它有点无害,但这种方法可能值得小心。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-11
  • 1970-01-01
  • 1970-01-01
  • 2014-11-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多