假设我有以下协议:

protocol Identifiable {
    var id: Int {get}
    var name: String {get}
}

我有以下 struct :

struct A: Identifiable {
    var id: Int
    var name: String
}

struct B: Identifiable {
    var id: Int
    var name: String
}

如你所见,我必须"遵守" struct A和 struct B中的可识别协议.但是想象一下,如果我还有N个 struct 需要遵守这个协议...我不想"复制/粘贴"一致性(变量id:Int,变量名称:String)

所以我创造了一个protocol extension:

extension Identifiable {
    var id: Int {
        return 0
    }

    var name: String {
        return "default"
    }
}

现在有了这个扩展,我可以创建一个符合可识别协议的 struct ,而不必实现两个属性:

struct C: Identifiable {

}

现在的问题是,我无法为id属性或name属性设置值:

var c: C = C()
c.id = 12 // Cannot assign to property: 'id' is a get-only property

这是因为在可识别协议中,id和名称只能获取.现在,如果我将id和name属性更改为{get set},则会出现以下错误:

Type 'C' does not conform to protocol 'Identifiable'

发生此错误是因为我没有在协议扩展中实现setter...所以我更改了协议扩展:

extension Identifiable {
    var id: Int {
        get {
            return 0
        }

        set {

        }
    }

    var name: String {
        get {
            return "default"
        }

        set {

        }
    }
}

现在错误消失了,但如果我将一个新值设置为id或name,它将获得默认值(getter).当然,the setter is empty.

我的问题是:

提前谢谢.

推荐答案

似乎您想通过协议扩展向类型添加stored property.但是,这是不可能的,因为使用扩展无法添加存储属性.

我可以给你看几个 Select .

子类化(面向对象编程)

最简单的方法(正如您可能已经想象的那样)是使用类而不是 struct .

class IdentifiableBase {
    var id = 0
    var name = "default"
}

class A: IdentifiableBase { }

let a = A()
a.name  = "test"
print(a.name) // test

缺点:在这种情况下,你的A类需要从IdentifiableBase继承,因为在Swift中没有多重继承,这将是唯一一个A类可以从IdentifiableBase继承的.

组件(面向协议的编程)

这种技术在游戏开发中非常流行

struct IdentifiableComponent {
    var id = 0
    var name = "default"
}

protocol HasIdentifiableComponent {
    var identifiableComponent: IdentifiableComponent { get set }
}

protocol Identifiable: HasIdentifiableComponent { }

extension Identifiable {
    var id: Int {
        get { return identifiableComponent.id }
        set { identifiableComponent.id = newValue }
    }
    var name: String {
        get { return identifiableComponent.name }
        set { identifiableComponent.name = newValue }
    }
}

现在你只需简单的书写就可以使你的字体符合Identifiable

struct A: Identifiable {
    var identifiableComponent = IdentifiableComponent()
}

测验

var a = A()
a.identifiableComponent.name = "test"
print(a.identifiableComponent.name) // test

Swift相关问答推荐

在同步参与者隔离上下文中调用参与者隔离实例方法

阴影动画的动画不流畅

.onReceive NSWindow.CloseNotify是否会为App中的每个窗口调用?

在SwiftUI中使用自定义图像填充列表行的正确方法

SWIFT并发:合并Taskgroup和AsyncStream?

按下一步后无法让文本字段切换焦点

是否可以循环遍历SWIFT子类并访问它们的静态变量S?

同时具有每个文本的标识符的文本组的可扩展性标识符

如何使用AsyncTimerSequence获取初始时钟,然后在指定的时间间隔内开始迭代?

如何在SwiftUI 4+(iOS 16+)中使用新的NavigationStack进行导航

使用变量(而非固定)的字符串分量进行Swift正则表达式

如何从 RC 加载场景作为 ModelEntity 而不是普通实体?

如何制作进度加载动画?

我怎样才能缩短(提高效率)这段代码?

您是否必须手动指定您的 DispatchQueue 是串行的?

如何将回调传递给 View init

如何根据 SwiftUI 中的字体大小定义按钮的大小?

如何在不阻塞 UI 更新的情况下使用 Swift Concurrency 在后台执行 CPU 密集型任务?

如何使被拖动的对象成为前景(foreground)对象

如何快速截取 UIView 的屏幕截图?