扩展符合协议的类和扩展基于相似条件的协议之间的区别是什么?

7

我正在查看这个链接。

但是我不太理解以下两个代码片段之间的逻辑差异:

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. 仅扩展符合协议的UIViewController的协议。

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

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

4
区别在于第一点:
extension UIViewController: ErrorPopoverRenderer { }

实际上,extends UIViewController类,所以每个UIViewController实例现在都可以访问协议中的方法和属性。这并不意味着它会扩展实现该协议的类,而是表示您正在为此类实现协议。通常情况下,您需要在该扩展中实现一些方法和属性。

第二段内容的位置:

extension ErrorPopoverRenderer where Self: UIViewController {}

你实际上为实现协议ErrorPopoverRendererUIViewController添加了方法和属性。
基本上,在第一个方式中,你通过实现整个协议来扩展类。而在第二种方式中,仅当这个类或子类实现了协议ErrorPopoverRenderer时,才会扩展该类。

1

1

首先,您创建了一个协议ErrorPopoverRenderer,并为方法presentError(...)创建了一个蓝图。然后,您扩展类UIViewController以符合此协议,通过实现(强制性)方法presentError(...)的蓝图。
这意味着您可以使用附加的协议约束ErrorPopoverRenderer为子类创建UIViewController的子类。如果UIViewController未被扩展以符合协议ErrorPopoverRenderer,则链接示例中随后的代码将导致编译时错误(...不符合协议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 或其子类使用而设计的话,那么上述解决方案就不太通用。

2

如果我们想要更广泛地使用ErrorPopoverRenderer,我们可以将每个可能使用该协议的类类型的具体蓝图放置在协议扩展中。这真的很方便,因为ErrorPopoverRenderer蓝图的方法presentError()的更具体部分可以针对可能符合协议的不同类别进行不同的指定,并且可以使方法presentError()更加简约。
我引用一个例子:

在此处使用Self表示,只有符合器从UIViewController继承时,该扩展才会发生。 这使我们能够假设ErrorPopoverRenderer确实是一个UIViewController,甚至不需要扩展UIViewController。

在这种方法中,由于代码现在知道(我们已经在1.中知道)将调用presentError()的是一个视图控制器,因此我们可以直接在蓝图实现中放置特定的UIViewController内容,而无需将其作为长列表的参数发送。
因此,对于这个特定的用途,2.是一种更“通用”的方法,意味着我们稍微减少了代码重复(从多个不同的UIViewController中调用presentError()而不是presentError(...很多参数...))。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接