ios – Swift – 协议扩展 – 属性默认值

假设我有以下协议:
protocol Identifiable {
    var id: Int {get}
    var name: String {get}
}

而且我有以下结构体:

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

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

可以看出,我必须“符合”struct A和struct B中的Identifiable协议.但是想象一下,如果我有N个更多的结构需要符合这个协议…我不想“复制/粘贴’一致性(var id:Int,var name:String)

所以我创建一个协议扩展:

extension Identifiable {
    var id: Int {
        return 0
    }

    var name: String {
        return "default"
    }
}

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

struct C: Identifiable {

}

现在的问题是我不能为id属性或name属性设置一个值:

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

发生这种情况是因为在可识别协议中,id和name只是gettable.现在,如果我将id和name属性更改为{get set}我得到以下错误

类型’C’不符合协议’可识别’

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

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

        set {

        }
    }

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

        set {

        }
    }
}

现在错误消失了,但如果我为id或name设置一个新值,它将获得认值(getter).当然,设定者是空的.

我的问题是:
我必须把什么代码放在设定器里面?因为如果我添加self.id = newValue它崩溃(递归).

提前致谢.

解决方法

看来你想通过协议扩展将一个存储的属性添加到类型.但是这是不可能的,因为扩展名不能添加存储的属性.

我可以给你几个选择.

子类(面向对象编程)

最简单的方法(可能你已经想象过)使用类而不是结构体.

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

class A: IdentifiableBase { }

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

Cons: In this case your A class needs to inherit from IdentifiableBase and since in Swift theres is not multiple inheritance this will be the only class A will be able to inherit from.

组件(面向协议的编程)

这种技术在游戏开发中非常受欢迎

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.name = "test"
print(a.name) // test

相关文章

UITabBarController 是 iOS 中用于管理和显示选项卡界面的一...
UITableView的重用机制避免了频繁创建和销毁单元格的开销,使...
Objective-C中,类的实例变量(instance variables)和属性(...
从内存管理的角度来看,block可以作为方法的传入参数是因为b...
WKWebView 是 iOS 开发中用于显示网页内容的组件,它是在 iO...
OC中常用的多线程编程技术: 1. NSThread NSThread是Objecti...