1

我想获取结构的指针,并获取或设置值。代码在这里

protocol TestProtocol {

}

struct TestStruct: TestProtocol {
    var username: String?
}

class TestViewModel {
    var testStruct: TestProtocol?

    func test() -> UnsafeMutablePointer<TestStruct?>? {
        guard let _ = self.testStruct as? TestStruct else {
            return nil
        }
        return withUnsafeMutablePointer(to: &(self.testStruct)) { (pointer) -> UnsafeMutablePointer<TestStruct?> in
            return pointer.withMemoryRebound(to: TestStruct?.self, capacity: MemoryLayout<TestStruct?>.size) { (point) -> UnsafeMutablePointer<TestStruct?> in
                return point
            }
        }
    }
}

func getvalue() {
     let testViewModel = TestViewModel()
     var testStruct = TestStruct()
     testStruct.username = "123"
     testViewModel.testStruct = testStruct
     print("\(testViewModel.test()?.pointee?.username)")
     // here print Optional(""), why not "123"?
}

get value 函数打印结果是错误的,但如果 TestStruct 只有一个 Int 的 var,结果是正确的。就像这样:

struct TestStruct: TestProtocol {
        var number: Int?
    }

func getvalue() {
         let testViewModel = TestViewModel()
         var testStruct = TestStruct()
         testStruct. number = 123
         testViewModel.testStruct = testStruct
         print("\(testViewModel.test()?.pointee?.username)")
         // Optional(123)
    }

为什么?如何解决?

4

1 回答 1

1

这是使用指向对象的指针制作/使用/完成的模式:

// this allocates memory for the pointer
let somePointer = UnsafeMutablePointer<someType>.allocate(capacity: 1)
// this initializes the memory to the value
somePointer.initialize(to: someInstanceOfSomeTime)
// this allows me to access the object
somePointer.pointee.someMethod(/* ... */)
// this destroys the memory
somePointer.deinitialize(count: 1)
somePointer.deallocate(capacity: 1)

由于您的内存可能包含直接或间接包含引用计数类型的类型,因此了解指针具有状态并且您需要管理所有这些状态的生命周期至关重要。

这是您的典型生命周期 - 已分配指针但其内容未初始化且不得使用 - 已初始化指针且现在可以使用其内容 - 已取消初始化指针且现在可能不再使用其内容但您可以再次初始化它 - 指针被释放并且可能不再被初始化。

了解这些步骤非常重要。当您使用典型的 swift 代码时,您正在执行所有这些步骤,但它们是隐式的。举个简单的例子:

public func printThingValue(t:Thing) {
    let aCopy = t.value
    print(aCopy)
}

让我们考虑 aCopy 的生命周期。在调用之前,aCopy 没有被分配。当您进入函数时,aCopy 被分配(在堆栈上)但未初始化。当分配发生时, aCopy 被初始化。调用 print 时,使用 aCopy。在printThingValue退出之前, aCopy 被取消初始化。当它退出时, aCopy 被释放(堆栈帧被破坏)。

知道这个生命周期非常重要,因为这正是指针使用的模型,但它不再是自动/隐式的。

与此相关的是问题的答案:我可以构造一个未初始化的值类型吗?答案是肯定的——有一种方法,那就是通过UnsafeMutablePointer。如果您调用allocate,您将获得代表您的值类型的未初始化内存,但这非常危险。如果你pointee在它被初始化之前分配给它,你需要 swift 编译器注入将破坏那里的值的代码。如果指向的类型包含引用类型,这将崩溃或导致未定义的行为。

了解和管理这些步骤是 Apple 试图让您可以使用指针的方式,但它会产生一系列新的危险:

- using an unallocated pointer (crash)
- using/assigning to an allocated but uninitialized pointer (crash)
- failing to deinitialize an initialized pointer (reference leak)
- failing to deallocate a deinitialized pointer (memory leak)
于 2017-06-07T17:24:44.927 回答