Tag: 协议扩展

具有不同行为的协议扩展

如您所知,您可以在该协议的扩展名中为协议方法提供默认实现。 但是,当您决定在协议中声明该方法或将其忽略时,您是否知道其中的含义? 我们将研究差异。 让我们从默认情况下不会发出声音的动物的协议定义开始。 协议动物{ func makeSound() } 扩展名动物{ func makeSound(){ 打印(“ [silence …]”) } } 然后,我们创建两个符合此协议Animal的对象Cat和Dog 。 他们俩都可以发出自己的声音: 猫:动物{ func makeSound(){ 打印(“喵!”) } } 狗类:动物{ func makeSound(){ 打印(“糟糕!”) } } 如果我们想创建动物的集合并想让它们全部说出来,我们可以创建一个像这样的数组: 让animal1 = Cat() 让animal2 = Dog() 让动物:[动物] = [动物1,动物2] 然后,我们可以遍历动物,让它们发出声音: 用于动物{ animal.makeSound() } 那么输出是什么? 是的…它将是喵! 和Wo! 但是,如果我们没有在协议中声明方法但保留默认实现,将会发生什么? 协议动物{} 扩展名动物{ func makeSound(){ 打印(“ [silence […]

从封装到协议扩展

假设我们要在Swift中定义一个简单的服务类,如果某些输入为正,则只输出一些输出。 (哇:要求跨度少于2行!) 对象封装 简单地说-容易完成吗? 是的,如果我们不在乎客户端的可扩展性: 使用这种方法,客户端类可以简单地实例化服务,并将doSomething工作委托给它。 非常简单(这很好),但是非常令人讨厌的是,当服务实例本身正在执行工作时,客户端无法干预要执行的输入数据和输出操作。 继承-不错的尝试! 不,继承并不总是我们的敌人。 它确实有(两个?)有效的用例。 但是恕我直言,这不是我们最好的朋友(即使代码确实更短!): 通过仅覆盖需要的内容,客户端可以将实现注入所需的位置。 每当定义时,服务将调用客户端替代而不是其自身的实现。 而且一切都会很顺利,例如,客户端现在不能是自定义的NSView (或UIView ),因为在这种情况下,有必要从所需的Cocoa基类而不是我们的服务中继承它…… 功能编程 哦! 我们正在变得现代化,是吗? 尽管如此,对于Swift而言,我也不认为这也是服务开发人员应该遵循的最佳方法-仅仅是因为这将(可能)需要在客户端开发人员级别上过多的基础设施意识。 确实,我们服务的用户需要执行一些“技巧”(例如,如果要在该处使用客户端状态,则捕获弱者或无主的 自我 ),以确保当他们将自定义闭包传递给我们时,不会在应用程序中引入内存泄漏: 代表和协议扩展 现在我们在说话! 我们最终将有一个真正的解决方案。 不需要继承,也不需要客户端开发人员的ARC知识! 我们只需要: 具有可选扩展名的服务委托协议,以提供我们要使用纯Swift公开的默认实现(即,没有@objc可选成员); 在服务中托管此类委托对象的弱实例或无主实例(尽管要求客户端类型为类,但无需我们的客户端开发人员处理内存管理问题); 并在适用时最终调用委托的(属性和)方法: 一体 最后,让我们看一看适用于我们所有类型客户的服务解决方案:如果喜欢继承,则接受; 否则,人们可以使用函数式编程并传递(设计良好)闭包; 或者,他们可以仅仅依靠(弱)聚集的代表来完成工作;或者 当然,所有这些都是为了防止默认情况下首先出现以下问题: 现在轮到你了。 您不需要上面的(我承认,很丑)多合一解决方案,但是至少您现在可以根据自己项目的需要对其进行调整。 无论如何,我想补充一点,我通常发现它足以支持继承和具有(部分或全部)默认实现的委托,但是有时功能样式也可以很好地工作(当您不希望客户需要在转义它们将通过的闭包)。