如何定义可以在协议扩展中设置和获取的变量
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
}
}
我来自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
}
}