【问题标题】:Difference between extending a class conforming to a protocol VS extending a protocol based on similar condition?扩展符合协议的类与基于类似条件扩展协议之间的区别?
【发布时间】:2015-12-26 15:31:33
【问题描述】:

我正在通过this link.

但我并没有真正理解以下两个代码 sn-ps 之间的逻辑区别:

1.仅扩展那些符合协议 ErrorPopoverRenderer 的 UIViewController。

protocol ErrorPopoverRenderer {
    func presentError(message: String, withArrow shouldShowArrow: Bool, backgroundColor: UIColor, withSize size: CGSize, canDismissByTappingAnywhere canDismiss: Bool)
} 

extension UIViewController: ErrorPopoverRenderer { //Make all the UIViewControllers that conform to ErrorPopoverRenderer have a default implementation of presentError
    func presentError(message: String, withArrow shouldShowArrow: Bool, backgroundColor: UIColor, withSize size: CGSize, canDismissByTappingAnywhere canDismiss: Bool) 
{}
} 

2。仅为符合它的 UIViewController 扩展协议。

extension ErrorPopoverRenderer where Self: UIViewController {
func presentError() {
}
}

无论哪种方式,任何符合协议的 UIViewController 子类都将具有默认方法实现,但在 UIviewcontroller 扩展或协议扩展中。 逻辑上的区别是什么? 如果我错了,请纠正我

【问题讨论】:

    标签: ios swift protocols


    【解决方案1】:

    区别在于第一个:

    extension UIViewController: ErrorPopoverRenderer { }
    

    实际上扩展 UIViewController 类,所以UIViewController 的每个实例现在都可以访问协议中的方法和属性。 这并不意味着它将扩展实现该协议的类,这意味着您现在正在为该类实现协议。通常你必须在那个扩展中实现一些方法和属性。

    第二个在哪里:

    extension ErrorPopoverRenderer where Self: UIViewController {}
    

    您实际上为实现ErrorPopoverRenderer 协议的UIViewController 添加了方法和属性。

    基本上,首先您使用整个协议实现扩展类,然后在第二个中扩展类,但如果此类或子类实现协议ErrorPopoverRenderer

    【讨论】:

      【解决方案2】:

      1

      首先,您为方法presentError(...) 创建一个带有蓝图 的协议ErrorPopoverRenderer。此后,您可以通过实现方法 presentError(...) 的(强制)蓝图来扩展类 UIViewController 以符合此协议。

      这意味着您可以将UIViewController) 子类化,并为子类添加额外的协议约束ErrorPopoverRenderer。如果UIViewController 没有被扩展以符合协议ErrorPopoverRenderer,那么您链接的示例中的后续代码将出​​现编译时错误(... does not comply to protocol ErrorPopoverRenderer

      class KrakenViewController: UIViewController, ErrorPopoverRenderer {
          func failedToEatHuman() {
              //…
              //Throw error because the Kraken sucks at eating Humans today.
              presentError(ErrorOptions(message: "Oh noes! I didn't get to eat the Human!", size: CGSize(width: 1000.0, height: 200.0))) //Woohoo! We can provide whatever parameters we want, or no parameters at all!
          }
      }
      

      但是,此方法可能存在问题,如您的链接所示:

      现在我们每次要呈现时都必须实现每个参数 错误视图。这种很糟糕,因为我们不能提供默认值 协议函数声明的值。

      因此ErrorPopoverRenderer 协议并非仅供UIViewController:s(或其子类)使用,因此上述解决方案不是很通用。

      2

      如果我们想要更广泛地使用ErrorPopoverRenderer,我们将特定蓝图用于每个可能使用该协议的类类型协议扩展 .这真的很简洁,因为方法 presentError()ErrorPopoverRenderer 蓝图的更具体部分可以为可能符合协议的不同类指定不同的方式,并且方法 presentError() 可以变得更加简约。

      我从例子中引用:

      在此处使用 Self 表示该扩展程序只会占用 当且仅当conformer从UIViewController继承时放置。 这使我们能够假设 ErrorPopoverRenderer 是 确实是一个 UIViewController,甚至没有扩展 UIViewController。

      在这个方法中,由于代码现在知道(我们已经在 1. 中知道了)它是一个将调用 presentError() 的视图控制器,我们可以放置特定的 UIViewController 内容直接在蓝图实现中,不需要将其作为长参数列表发送。

      因此,对于这种特定用途,2. 是一种更“通用”的方法,从某种意义上说,我们略微减少了代码重复(从几个不同的 UIViewController:s 调用 presentError()presentError(... lots of args ...)) .

      【讨论】:

        猜你喜欢
        • 2017-06-03
        • 2013-05-19
        • 2015-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多