如何构建一个可以控制其存储属性可变性的 Swift 对象
How to build a Swift object that can control the mutability of its stored properties
我想创建一组具有以下行为的对象:
- 每个都有一个 BOOL 属性 -- 称之为
dataLocked
-- 最初是假的。
- 每个都有一组存储的属性,只要
dataLocked == false
. ,其值就可以设置,但不能读取
- 每当
dataLocked == true
时,可以读取这些相同的存储属性,但不能设置它们
dataLocked
只能设置一次
下面是一个示例实现。是否有任何 Swifty 方法可以实现这一点,而不必为每个对象的每个 属性 重现所有这些获取和设置条件?
我认为最简洁的解决方案是创建一个 属性 包装器,但我还没有找到任何方法让包装器根据封闭对象中的“锁定”属性 的值更改其行为.
class ImmutableObjectBase {
var dataLocked: Bool = false {
didSet { dataLocked = true }
}
private var _someIntValue: Int = 42
var someIntValue: Int {
get {
precondition(dataLocked, "Cannot access object properties until object is locked")
return _someIntValue
}
set {
precondition(!dataLocked, "Cannot modify object properties after object is locked")
_someIntValue = newValue
}
}
}
let i = ImmutableObjectBase()
i.someIntValue = 100
i.dataLocked = true // or false, it doesn't matter!
print (i.someIntValue) // 100
print (i.dataLocked) // true
i.someIntValue = 200 // aborts
我找到了解决您问题的方法,但这可能不是最干净的方法。
如果您检查 this,您可能会找到更好的方法
或 this.
我使用这个 tutorial:
设法锁定和解锁属性
import Foundation
import Combine
public class Locker: ObservableObject {
@Published public var isLocked = false
public static let shared = Locker()
private init() {}
}
@propertyWrapper
struct Lockable<Value> {
private var _wrappedValue: Value
init(wrappedValue: Value) {
self._wrappedValue = wrappedValue
}
var wrappedValue: Value {
get {
precondition(Locker.shared.isLocked, "Cannot access object properties until object is locked")
return _wrappedValue
}
set {
precondition(!Locker.shared.isLocked, "Cannot modify object properties after object is locked")
_wrappedValue = newValue
}
}
}
class ImmutableObjectBase {
var isLocked: Bool = false {
didSet {
Locker.shared.isLocked = self.isLocked
}
}
@Lockable var someString: String = "initial"
@Lockable var someInt: Int = 1
}
var i = ImmutableObjectBase()
i.isLocked = true
print(i.someInt, i.someString) // 1, initial
i.isLocked = false
i.someInt = 2
i.someString = "new value"
i.isLocked = true
print(i.someInt, i.someString) // 2, new value
编辑:
我刚刚发现了一个类似的问题,并且有一个可接受的答案。
检查
import Foundation
protocol PropertyWrapperWithLockableObject {
var enclosingObject: LockableObjectBase! {get set}
}
@propertyWrapper
class Lockable<Value>: PropertyWrapperWithLockableObject {
private var _wrappedValue: Value
var enclosingObject: LockableObjectBase!
init (wrappedValue: Value) { self._wrappedValue = wrappedValue }
var wrappedValue: Value {
get {
precondition(enclosingObject.isLocked, "Cannot access object properties until object is locked")
return _wrappedValue
}
set {
precondition(!enclosingObject.isLocked, "Cannot modify object properties after object is locked")
_wrappedValue = newValue
}
}
}
class LockableObjectBase {
internal var isLocked: Bool = false {
didSet { isLocked = true }
}
init () {
let mirror = Mirror(reflecting: self)
for child in mirror.children {
if var child = child.value as? PropertyWrapperWithLockableObject {
child.enclosingObject = self
}
}
}
}
用法:
class DataObject: LockableObjectBase {
@Lockable var someString: String = "Zork"
@Lockable var someInt: Int
override init() {
someInt = 42
// super.init() // Not needed in this particular example.
}
}
var testObject = DataObject()
testObject.isLocked = true
print(testObject.someInt, testObject.someString) // 42, Zork
testObject.isLocked = false // Has no effect: Object remained locked
print (testObject.isLocked) // true
testObject.someInt = 2 // Aborts the program
arsenius 的回答 提供了重要的反思线索!
我想创建一组具有以下行为的对象:
- 每个都有一个 BOOL 属性 -- 称之为
dataLocked
-- 最初是假的。 - 每个都有一组存储的属性,只要
dataLocked == false
. ,其值就可以设置,但不能读取
- 每当
dataLocked == true
时,可以读取这些相同的存储属性,但不能设置它们
dataLocked
只能设置一次
下面是一个示例实现。是否有任何 Swifty 方法可以实现这一点,而不必为每个对象的每个 属性 重现所有这些获取和设置条件?
我认为最简洁的解决方案是创建一个 属性 包装器,但我还没有找到任何方法让包装器根据封闭对象中的“锁定”属性 的值更改其行为.
class ImmutableObjectBase {
var dataLocked: Bool = false {
didSet { dataLocked = true }
}
private var _someIntValue: Int = 42
var someIntValue: Int {
get {
precondition(dataLocked, "Cannot access object properties until object is locked")
return _someIntValue
}
set {
precondition(!dataLocked, "Cannot modify object properties after object is locked")
_someIntValue = newValue
}
}
}
let i = ImmutableObjectBase()
i.someIntValue = 100
i.dataLocked = true // or false, it doesn't matter!
print (i.someIntValue) // 100
print (i.dataLocked) // true
i.someIntValue = 200 // aborts
我找到了解决您问题的方法,但这可能不是最干净的方法。 如果您检查 this,您可能会找到更好的方法 或 this.
我使用这个 tutorial:
设法锁定和解锁属性import Foundation
import Combine
public class Locker: ObservableObject {
@Published public var isLocked = false
public static let shared = Locker()
private init() {}
}
@propertyWrapper
struct Lockable<Value> {
private var _wrappedValue: Value
init(wrappedValue: Value) {
self._wrappedValue = wrappedValue
}
var wrappedValue: Value {
get {
precondition(Locker.shared.isLocked, "Cannot access object properties until object is locked")
return _wrappedValue
}
set {
precondition(!Locker.shared.isLocked, "Cannot modify object properties after object is locked")
_wrappedValue = newValue
}
}
}
class ImmutableObjectBase {
var isLocked: Bool = false {
didSet {
Locker.shared.isLocked = self.isLocked
}
}
@Lockable var someString: String = "initial"
@Lockable var someInt: Int = 1
}
var i = ImmutableObjectBase()
i.isLocked = true
print(i.someInt, i.someString) // 1, initial
i.isLocked = false
i.someInt = 2
i.someString = "new value"
i.isLocked = true
print(i.someInt, i.someString) // 2, new value
编辑:
我刚刚发现了一个类似的问题,并且有一个可接受的答案。
检查
import Foundation
protocol PropertyWrapperWithLockableObject {
var enclosingObject: LockableObjectBase! {get set}
}
@propertyWrapper
class Lockable<Value>: PropertyWrapperWithLockableObject {
private var _wrappedValue: Value
var enclosingObject: LockableObjectBase!
init (wrappedValue: Value) { self._wrappedValue = wrappedValue }
var wrappedValue: Value {
get {
precondition(enclosingObject.isLocked, "Cannot access object properties until object is locked")
return _wrappedValue
}
set {
precondition(!enclosingObject.isLocked, "Cannot modify object properties after object is locked")
_wrappedValue = newValue
}
}
}
class LockableObjectBase {
internal var isLocked: Bool = false {
didSet { isLocked = true }
}
init () {
let mirror = Mirror(reflecting: self)
for child in mirror.children {
if var child = child.value as? PropertyWrapperWithLockableObject {
child.enclosingObject = self
}
}
}
}
用法:
class DataObject: LockableObjectBase {
@Lockable var someString: String = "Zork"
@Lockable var someInt: Int
override init() {
someInt = 42
// super.init() // Not needed in this particular example.
}
}
var testObject = DataObject()
testObject.isLocked = true
print(testObject.someInt, testObject.someString) // 42, Zork
testObject.isLocked = false // Has no effect: Object remained locked
print (testObject.isLocked) // true
testObject.someInt = 2 // Aborts the program
arsenius 的回答