【发布时间】:2017-03-14 23:22:46
【问题描述】:
我试图通过指向该属性的指针来获取/设置对象的计算属性。我在下面包含了代码 sn-p 和输出。
sn-p 的要点是有一个类Foo 具有一个计算属性bar。 Mutator 类保留一个指针,并有一个计算属性 value,它只是获取/设置它指向的值。所以,如果我创建f1: Foo,然后创建一个引用f1.bar 的m1: Mutator 对象,我认为设置m1.value 也会设置f1.bar1。它有时有效,但并非总是如此。
//---------------------------------------------------------------------------
// Class definitions
class Foo
{
private var data = [String: Double]()
var bar: Double?
{
get { return self.data["bar"] }
set { self.data["bar"] = newValue }
}
init(_ key: String, _ val: Double)
{
self.data[key] = val
}
}
class Mutator
{
let name: String
let storage: UnsafeMutablePointer<Double?>
var value: Double?
{
get { return self.storage.pointee }
set { self.storage.pointee = newValue}
}
init(name: String, storage: UnsafeMutablePointer<Double?>)
{
self.name = name
self.storage = storage
}
}
//---------------------------------------------------------------------------
// Create and display mutators directly
print("-\nCreate and display mutator directly")
let f1 = Foo("bar", 1.1)
let f2 = Foo("bar", 2.2)
let f3 = Foo("bar", 3.3)
let m1 = Mutator(name:"mf1", storage: &f1.bar) // Or, let m1 = Mutator(name:"f1", storage: UnsafeMutablePointer<Double?>(&f1.bar))
let m2 = Mutator(name:"mf2", storage: &f2.bar)
let m3 = Mutator(name:"mf3", storage: &f3.bar)
var before = m1.value
m1.value = 199.1
var after = m1.value
print("\(m1.name): before=\(before), after=\(after) @ \(m1.storage)")
before = m2.value
m2.value = 299.2
after = m2.value
print("\(m2.name): before=\(before), after=\(after) @ \(m2.storage)")
before = m3.value
m3.value = 299.2
after = m3.value
print("\(m3.name): before=\(before), after=\(after) @ \(m3.storage)")
//---------------------------------------------------------------------------
// Create mutators inside function
func createMutators() -> [Mutator]
{
print("-\nIn createMutators function ...")
let m1 = Mutator(name:"mf1", storage: &f1.bar)
let m2 = Mutator(name:"mf2", storage: &f2.bar)
let m3 = Mutator(name:"mf3", storage: &f3.bar)
print("\(m1.name)=\(m1.value) @ \(m1.storage)")
print("\(m2.name)=\(m2.value) @ \(m2.storage)")
print("\(m3.name)=\(m3.value) @ \(m3.storage)")
return [m1, m2, m3]
}
let mutator = createMutators()
//---------------------------------------------------------------------------
// Display mutators returned by function
print("-\nDisplay mutator returned by function")
for m in mutator
{
let before = m.value
m.value = 10.0 + (before ?? Double.nan)
let after = m.value
print("\(m.name): before=\(before), after=\(after) @ \(m.storage)")
}
如果我在 Linux 上运行上述代码,我会得到以下输出:
Create and display mutator directly
mf1: before=Optional(1.1000000000000001), after=Optional(199.09999999999999) @ 0x00007ffd38f82730
mf2: before=Optional(2.2000000000000002), after=Optional(299.19999999999999) @ 0x00007ffd38f82708
mf3: before=Optional(3.2999999999999998), after=Optional(299.19999999999999) @ 0x00007ffd38f826e0
-
In createMutators function ...
mf1=Optional(1.1000000000000001) @ 0x00007ffd38f82288
mf2=Optional(2.2000000000000002) @ 0x00007ffd38f82260
mf3=Optional(3.2999999999999998) @ 0x00007ffd38f82238
-
Display mutator returned by function
mf1: before=Optional(4.9406564584124654e-324), after=Optional(10.0) @ 0x00007ffd38f82288
mf2: before=Optional(6.9527664311957093e-310), after=Optional(10.0) @ 0x00007ffd38f82260
mf3: before=nil, after=Optional(nan) @ 0x00007ffd38f82238
第一个输出块显示预期的行为。第二个块指向不同的地址,这是出乎意料的。更奇怪的是,尽管地址错误,但它读取了正确的值。最后一个输出块与第二个块具有相同的地址,但读取不同的初始值,尽管它确实设法正确设置和读回值。
我知道这可能是对计算属性和指针的滥用。但是谁能解释为什么它有时会起作用?为什么在函数中创建它会给它一个不同的地址?当地址相同时,为什么在函数中读取它并在返回后给出不同的答案?有没有办法让这个工作?
只是为了进一步混淆:以上是在 Linux 上运行的。当我在 Mac 上尝试这个实验时,我得到了一些不同的结果,尽管总体观察有时它有效。
【问题讨论】:
-
这就是 UnsafeMutablePointer 中的 Unsafe。 :)
-
很难看出你想在什么环境下做,本质上是在涉及 Swift / iOS 环境的任何事情中的“性能编程”。如果这是爱好(很棒),(去吧)[opencores.org]! :) 正如 hotpaw 所解释的那样,即使在 Swift 中,您也可以非常容易地抓住一块 ram 内存并自己搞砸——这也许就是您要走的路?享受吧。
-
是的,只是在玩耍和试验。谢谢!
标签: swift