扩展符合协议的类VS扩展基于相似条件的协议的区别?

时间:2015-12-26 15:31:33

标签: ios swift protocols

我正在经历this link.

但我真的没有得到以下两个代码片段之间的逻辑差异:

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

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。仅为那些符合它的UIViewControllers扩展协议。

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

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

2 个答案:

答案 0 :(得分:4)

区别在于第一个:

extension UIViewController: ErrorPopoverRenderer { }

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

第二个位置:

extension ErrorPopoverRenderer where Self: UIViewController {}

你实际上添加了方法&实现协议UIViewController的{​​{1}}的属性。

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

答案 1 :(得分:1)

1

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

这意味着您可以为子类使用附加协议约束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!
    }
}

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

  

现在我们每次要呈现时都必须实现每个参数   一个ErrorView。这种情况很糟糕,因为我们无法提供默认值   协议函数声明的值。

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

<强> 2

如果我们希望更广泛地使用ErrorPopoverRenderer,我们会为可能在协议扩展中使用协议的每个类类型放置特定的蓝图。这非常简洁,因为可以为可能符合协议的不同类指定方法ErrorPopoverRenderer的{​​{1}}蓝图的更具体部分,并且可以制作方法presentError()更简约。

我引用了一个例子:

  

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

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

因此,对于这种特定用途,2是一种更“通用”的方法,在某种意义上我们稍微减少了代码重复(从几个不同的{{调用presentError() vs UIViewController 1}}:秒)