gpt4 book ai didi

Swift 协议(protocol)导致无效的重新声明和困惑的函数表

转载 作者:搜寻专家 更新时间:2023-10-31 22:36:58 28 4
gpt4 key购买 nike

TLDR:在大型项目中使用许多 Swift 协议(protocol)非常适合测试和 SOLID 编码,但我遇到了函数困惑和无效的重新声明冲突。在大量使用协议(protocol)的同时避免 Swift 中的这些问题的最佳实践是什么?


具体来说,我想使用协议(protocol)将职责与 View 类分开,这样它们就不需要了解用于“装饰”它们的数据模型的任何信息。但这为我的数据模型类创建了很多函数,这些函数在整个应用程序中公开,并且开始与其他协议(protocol)发生冲突。

举个例子,假设我想根据我项目中的某个数据模型设置我的自定义 tableview 单元格。我们称它为 MyDataModel。我创建了一个这样的装饰协议(protocol):

protocol MyCellDecorator {
var headingText: String?
var descriptionText: String?
}

然后我的手机就像

class MyCell: UITableViewCell {
@IBOutlet weak var headingLabel: UILabel!
@IBOutlet weak var descriptionLabel: UILabel!

func setup(fromDecorator decorator: MyCellDecorator) {
headingLabel.text = decorator.headingText
descriptionLabel.text = decorator.descriptionText
}
}

现在我需要做的就是提供一个实现 MyCellDecorator 的数据模型类的扩展,提供 headingTextdescriptionText,我可以将我的数据模型对象插入 setup(fromDecorator:)

extension MyDataClass: MyCellDecorator {
var headingText: String {
return “Some Heading“
}
var descriptionText: String {
return “Some Description“
}
}

这使得电池易于测试;它清楚地分离了职责,MyCell 和驱动它的 UIViewController 现在不需要了解 MyDataModel..

但现在 MyDataModel 有两个额外的属性,headingTextdescriptionText - 随处可用。但是 MyDataModel 已经在我的项目中为特定的 UI 扩展了 10 个其他装饰器协议(protocol),碰巧另一个协议(protocol)已经定义了 headingText,所以我得到编译错误“invalid redeclaration of '标题文本'”。

考虑到所有这些令人头疼的问题,我决定放弃,继续前进,将 MyDataModel 传递给 MyCell,它全部编译,但我失去了所有上述优势。

在像这样的大项目中,有什么好的方法可以在不弄乱我的类的函数表和不同扩展之间发生重新声明冲突的情况下获得那些甜蜜的协议(protocol)胜利?

最佳答案

我同意 Andrey 的发展方向,但我相信它更简单。您只需要装饰器类型,以及您描述它们的方式,它们应该能够是简单的结构,而不需要固有的协议(protocol)。

struct MyCellDecorator {
let headingText: String
let descriptionText: String
}

(我已将这些设置为非可选,我强烈建议除非您在 UI 上区分“空字符串”和“无”。)

扩展的工作方式与您之前所做的几乎完全一样:

extension MyDataClass {
func makeMyCellDecorator() -> MyCellDecorator {
return MyCellDecorator(headingText: "Some Heading",
description: "Some Description")
}
}

在某些情况下,您可能会发现模型对象生成装饰器的方式非常一致。这是协议(protocol)允许您提取代码的地方,例如:

protocol MyCellDecoratorConvertible {
var headingText: String { get }
var descriptionText: String { get }
}

extension MyCellDecoratorConvertible {
func makeMyCellDecorator() -> MyCellDecorator {
return MyCellDecorator(headingText: headingText,
description: description)
}
}

此示例捕获了单元格恰好已经具有完全正确的名称的情况。然后你只需要添加 MyCellDecoratorConvertible 并且该属性是免费的。

所有这一切的关键在于,您将拥有 model.makeMyCellDecorator().headingText 而不是 model.headingText,这将解决您的爆炸式增长属性。

请注意,每次您访问它时都会生成一个新的装饰器,这就是我使用 make ( factory ) 命名约定的原因。您可能会考虑其他方法,例如 AnyMyCellDecorator 类型的橡皮擦(但我会从简单开始;这些类型可能非常小,复制它们并不昂贵)。

您可以将 UI 拆分为模块并使用内部扩展。这些不会出现在其他模块中,这将阻止 myCellDecorator 出现在任何地方。如果更方便,您可以将 myCellDecorator 扩展与 MyCell 放在同一个文件中,并将它们标记为私有(private)。

由于这是一个庞大的现有代码库,我强烈建议允许任何现有代码重复来驱动您的设计。没有一种模式适用于所有系统。甚至没有必要让每个装饰器都遵循完全相同的模式(在某些情况下使用协议(protocol)可能更有意义;在其他情况下使用结构;在其他情况下您可能需要两者)。您可以创建一种模式“语言”,而不必仅仅因为“这就是模式”而将自己禁锢在创建额外协议(protocol)的世界中。

关于Swift 协议(protocol)导致无效的重新声明和困惑的函数表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56289956/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com