我正在经历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扩展或协议扩展中。 什么是逻辑差异? 如果我错了,请纠正我
答案 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}}:秒)