如何定义可以在协议扩展中设置和获取的变量

How to define variable that can be set and get in extension of protocol

我来自Java世界。现在我正在编程 Swift 4.

我想在Swift中实现抽象class,我知道在Swift中没有抽象class这样的概念。但我知道我们可以通过使用协议在 Swift 中模仿这个概念。例如,这是我尝试过的:

// With protocol, I can define functions that concrete class have to implement
protocol ProductProvider {
   func getProductNumber() -> Int
}

// with protocol extension, I can define shared (computed) properties and functions among concrete classes that comply with this protocol
extension ProductProvider {
  var maxProductCount: Int {
        return 10
  }
}

但是现在,我想要一个可以设置和获取的共享变量("shared" 意味着与符合此协议的 classes 共享):

extension ProductProvider {
  var maxProductCount: Int {
        set(newValue) {
           // set to what if I couldn't define private stored variable in extension to hold the most recent set value ?
        }
        get{
           // how to return the most recent value set?
        }
  }
}

我的问题在上面代码的注释中。我如何在 Swift 4 中设置和获取协议扩展中的变量?如果不可能,有什么解决方法?

除了讨论它是否是实现您想要的目标的正确方法之外,您还可以使用对象关联。

public final class ObjectAssociation<T: AnyObject> {

    private let policy: objc_AssociationPolicy

    /// - Parameter policy: An association policy that will be used when linking objects.
    public init(policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN_NONATOMIC) {

        self.policy = policy
    }

    /// Accesses associated object.
    /// - Parameter index: An object whose associated object is to be accessed.
    public subscript(index: AnyObject) -> T? {

        get { return objc_getAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque()) as! T? }
        set { objc_setAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque(), newValue, policy) }
    }
}

并在您的分机中

extension SomeType {

    private static let association = ObjectAssociation<NSObject>()

    var simulatedProperty: NSObject? {

        get { return SomeType.association[self] }
        set { SomeType.association[self] = newValue }
    }
}

无法直接通过对象关联存储 Swift 类型。您可以存储例如NSNumber 而不是 Int。
资料来源:

我认为最简单的方法是使用 getter 和 setter 在协议中定义变量。然后在您的符合对象中,您应该将变量声明为符合。 一个例子:

protocol AbstractObject {

    var maxProductCount: Int { get set }
}

struct ConformObject: AbstractObject {

    var maxProductCount: Int
}

现在您可以在默认实现中使用您的变量

extension AbstractObject {

    mutating func addOne() -> Int {
        self.maxProductCount += 1
        return self.maxProductCount
    }
}