我想为swift 中的类的所有属性重写一次setter/getter
这是我的课。每次添加新值时,我都想调用Realm
class House : Object
{
var a:String
{
set {
do {
let realm = try Realm()
try realm.write {
a = newValue
}
}
catch {
}
}
}
var b:String
{
set {
do {
let realm = try Realm()
try realm.write {
b = newValue
}
}
catch {
}
}
}
}
在Swift中,无法同时覆盖所有属性的setter。
不过,你通常可以做的是使用:
- 每个属性覆盖的setter
- 抽象计算属性包装低级属性
- 通过KVC访问器方法(例如
is<Key>
、get<Key>
…)拦截getter和setter,并且如果您想应用修饰行为(出于此原因,您可能希望避免),则仅通过valueForKey(Path):
依赖于基于KVC的非类型动态访问
但是Realm在后台使用自定义getter和setter,它们在运行时在动态插入的中间类中被动态覆盖,并依赖于它们的存在。因此,唯一可行的方法是声明dynamic
存储的属性,并在这些属性的基础上为每个属性添加一个额外的属性。
var storedPropertyA: String = ""
var computedPropertyA: String {
get {
// add your extra behavior here
return storedPropertyA
}
set {
// add your extra behavior here
self.storedPropertyA = newValue
}
}
除此之外,还有一种使用decorator模式并用额外行为装饰整个对象的替代方法。在Swift中,您可以让对象和装饰器实现一个通用协议,该协议定义您的属性。
protocol HousingProperties {
var a: String { get set }
}
class House: HousingProperties {
var a: String = ""
}
class HouseDecorator: HousingProperties {
internal var house: House
init(house: House) { self.house = house }
var a: String {
// add your extra behavior here
self.house.a = a
}
}
尽管如此,我还是NOT建议出于此处的目的拦截属性setter和getter。相反,我建议以某种方式构建应用程序的体系结构,使您能够意识到是否存在写事务,并将编写写事务的责任交给试图修改对象的代码。
让我解释一下原因:Realm正在使用多版本并发控制算法来管理持久数据并实现线程安全。这确保不同的线程可以在任何时间点读取数据,而不必读取锁并尝试同步这些数据。相反,当写入发生时,所有访问者都会收到有新数据的通知,并尝试转到最新的事务。在此之前,线程仍在使用的最旧数据版本和写入的数据版本之间的所有版本都必须保留。当所有线程都推进了它们的提交指针时,它们可以首先被释放。如果你做了很多小事务,你的文件大小可能会被炸到不必要的高值。因此,我们建议将事务批量写入大型变更集。
有一种方法可以达到海报想要的效果,但可能不可取。。。无论如何你可以创建你自己的赋值操作符,在赋值之前,它可以在领域中执行你想做的任何事情
class MyType {
var myInt : Int = 0
var myString : String = ""
init(int: Int, string: String) {
myInt = int
myString = string
}
}
infix operator === {}
func ===<T>(lhs: T, rhs: T) -> T? {
Realm() // replace with whatever Realm()-specific stuff you want to do
return rhs
}
protocol MyAddableTypes {
func + (lhs: Self, rhs: Self) -> Self
}
extension String : MyAddableTypes {}
extension Int : MyAddableTypes {}
infix operator +== {} // ... -== similarily
func +==<T: MyAddableTypes>(lhs: T, rhs: T) -> T? {
Realm() // replace with whatever Realm()-specific stuff you want to do
return lhs+rhs
}
func Realm() {
// ...
print("Called realm")
}
var a = MyType(int: 1, string: "foo")
a.myString === "bar" // calls Realm(). After operation: a.myString = "bar"
a.myInt +== 1 // calls Realm(). After operation: a.myInt = 2
我想我还应该提到,如果你只想在值为set时执行"Realm stuff"(从你的示例:previor到设置值),那么与存储属性一起使用的willSet
方法不需要看起来那么乱(嵌套闭包),就我个人而言,我更喜欢这种方法
func Realm() {
print("Called realm")
}
class MyType {
// This isn't so messy, is it?
var myInt : Int = 0 { willSet { priorToSetValue(newValue) } }
var myString : String = "" { willSet { priorToSetValue(newValue) } }
var myDouble : Double = 0.0 { willSet { priorToSetValue(newValue) } }
private func priorToSetValue<T> (myVar: T) {
// replace with whatever Realm()-specific stuff you want to do,
// possibly including doing something with your new value
Realm()
}
init(int: Int, double: Double, string: String) {
myInt = int
myDouble = double
myString = string
}
}
var a = MyType(int: 1, double: 1.0, string: "foo")
a.myString = "bar"
print(a.myString) // calls Realm(). After operation: a.myString = "bar"
a.myInt += 1 // calls Realm(). After operation: a.myInt = 2