【问题标题】:Generating auto-incrementing Instance IDs in Swift using Protocols and protocol-extensions only仅使用协议和协议扩展在 Swift 中生成自动递增的实例 ID
【发布时间】:2021-05-27 02:31:22
【问题描述】:

目标

创建具有以下行为的“AutoIDable”协议。

  1. 符合此协议的类的每个实例都将获得一个自动生成的字符串类型的“id”属性。
  2. 代码应生成格式为<prefix><Instance-count-starting-from-1> 的id 字符串(例如:E-1E-2、...E-<n> 等等,用于符合类的第一个、第二个...第 n 个实例。
  3. 协议和协议扩展应该所有完成生成id字符串所需的工作。符合标准的类只需订阅协议即可。

当前状态:

我通过以下实现实现了目标 1 和目标 2:

protocol Identifiable {
    var id: String { get }
}

protocol AutoIDable: Identifiable{
    static var _instanceCount: Int { get set }
}

class AutoID: AutoIDable {
    init(idPrefix: String) {
        setAutoID(prefix: idPrefix)
    }

    internal static var _instanceCount: Int = 0
    var id: String = ""
    
    func setAutoID(prefix: String = ""){
        Self._instanceCount += 1
        self.id = "\(prefix)\(Self._instanceCount)"
    }
}

class Employee: AutoID {
    init(){
        super.init(idPrefix: "E-")
    }
}

let e1 = Employee()
let e2 = Employee()
let e3 = Employee()
print(e1.id)
print(e2.id)
print(e3.id)
print(e1.id)

运行上述代码的输出:

E-1
E-2
E-3
E-1

待办事项:

为了实现目标 3,我需要消除 AutoID 超类并使用协议扩展实现相同的功能。

我遇到了麻烦,因为:

  1. 协议扩展不允许静态存储属性。我确实知道如何在不使用超类的情况下解决此限制。
  2. 我不知道如何将代码注入到 Employee 类的创建者可能创建的所有初始化程序中。同样,我想不出不使用超类的解决方法。

如果您能指出正确的方向,我将不胜感激。

PS:Swift 编程新手。如果您对以更“迅速”的方式实现代码有任何建议,请告诉我。 :-)

【问题讨论】:

  • 这是不可能的。协议不应该添加存储属性。这不是他们的设计目的(我想也有技术原因)。您应该继续使用您的超类,或者在每个符合要求的类中添加该属性声明。

标签: swift swift-protocols


【解决方案1】:

由于您要使用协议,因此您不能在协议中拥有存储的属性。因此,如果不是 ID 本身,您将需要一些地方来存储递增的 ID 值。

不确定它是否违反了您只使用协议的要求,因为它需要一个类型来存储,但至少它不需要符合标准的类来拥有超类。

所以,假设我们构建了一个包含所有 ID 并保持递增计数器的类:

class AutoIncrementId {
    static private var inc: Int = 0
    static private var ids: [ObjectIdentifier: String] = [:]

    static func getId(_ objectId: ObjectIdentifier, prefix: String) -> String {
        if let id = ids[objectId] { return id }
        else {
            inc += 1
            let id = "\(prefix)\(inc)"
            ids[objectId] = id
            return id
        }
    }
}

那么协议要求可以是:

protocol AutoIdentifiable {
    static var prefix: String { get }
    var id: String { get }
}

所以,一个类需要定义它的前缀。但我们可以为id 定义一个默认实现:

extension AutoIdentifiable where Self: AnyObject {
    var id: String {
        AutoIncrementId.getId(ObjectIdentifier(self), prefix: Self.prefix)
    }
}

用法是:

class Employee: AutoIdentifiable {
   static let prefix = "E-"
}

let e1 = Employee()
let e2 = Employee()
let e3 = Employee()
print(e1.id)  // E-1
print(e2.id)  // E-2
print(e3.id)  // E-3
print(e1.id)  // E-1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多