如何创建可展示多类型对象的SwiftUI复用视图?
SwiftUI视图复用方案咨询
现有如下SwiftUI视图代码:
struct CardView: View { let item: Items var body: some View { VStack(alignment: .center) { Text("\(item.name)") .font(.headline) .accessibilityAddTraits(.isHeader) Spacer() HStack { Label("\(item.description)", systemImage: "questionmark.square.dashed") } .font(.caption) } .padding() } } struct CardView_Previews: PreviewProvider { static var item = Items.abilityScores[0] static var previews: some View { CardView(item: item) .previewLayout(.fixed(width: 400, height: 60)) } }
(Items.abilityScores是自定义类文件中生成的Items类型列表)
我希望复用该视图展示多种不同类型的对象,目前想到几种实现思路:
- 为
Item创建基类,让其他拥有更多属性的类继承它,再传入视图中,但不确定是否可行。 - 为每个类型单独创建类及对应的视图,尽管它们的实现与用法非常相似。
- 其他方案?比如将参数设为
AnyObject,确保所有对象拥有相同字段名,在展示前检查字段是否存在。
请问方案1是否可行?还是只能选择方案2重复创建相似视图?
解答
方案1的可行性
方案1可行,但在Swift中并非最优选择。如果你的各类对象都是类(Class)而非结构体(Struct),可以定义一个包含name和description属性的基类,让其他类继承它,之后CardView的参数类型改为这个基类即可。示例如下:
class BaseItem { let name: String let description: String init(name: String, description: String) { self.name = name self.description = description } } // 子类示例 class AbilityScore: BaseItem { let value: Int init(name: String, description: String, value: Int) { self.value = value super.init(name: name, description: description) } } // 修改后的CardView struct CardView: View { let item: BaseItem var body: some View { // 原有视图代码不变 } }
但Swift更推荐使用**协议(Protocol)**而非类继承,尤其是当你的数据类型可能是结构体时(结构体不支持继承),协议的灵活性更高。
更优方案:使用协议
定义一个协议,要求实现name和description属性,让所有需要展示的类型遵循该协议,这样CardView可以接收任意遵循该协议的类型,不管是类还是结构体:
protocol CardDisplayable { var name: String { get } var description: String { get } } // 让原有Items类型遵循协议 extension Items: CardDisplayable {} // 其他类型也遵循协议,比如结构体 struct Weapon: CardDisplayable { let name: String let description: String let damage: Int } // 修改CardView struct CardView: View { let item: any CardDisplayable var body: some View { // 原有视图代码不变 } }
这种方式无需继承,支持值类型(结构体)和引用类型(类),完全符合Swift的设计理念,是复用视图的最佳实践。
方案3的问题
使用AnyObject并检查字段存在的方式不推荐:
- 失去编译时类型安全,容易因字段名拼写错误导致运行时崩溃。
- 代码可读性差,需要大量的类型转换和可选绑定,维护成本高。
方案2的弊端
为每个类型单独创建视图会导致大量重复代码,违背DRY(Don't Repeat Yourself)原则,后续修改UI逻辑时需要在多个地方同步修改,极易出错。
内容的提问来源于stack exchange,提问作者phroureo
相关产品推荐
相关产品推荐

