Swift Используйте UnsafeMutablePointer of Struct, чтобы получить значение String Error

Я хочу получить указатель структуры и получить или установить значение. код здесь

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, результат будет правильным. Просто так:

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)
    }

Зачем? как это исправить?

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)

Поскольку ваша память может содержать тип, который прямо или косвенно содержит тип с подсчетом ссылок, крайне важно, чтобы вы понимали, что указатели имеют состояние, и вам необходимо управлять временем жизни всех этих состояний.

Это ваше обычное время жизни - указатель выделен, но его содержимое не инициализировано и не должно использоваться - указатель инициализирован и его содержимое теперь может использоваться - указатель деинициализирован, и теперь его содержимое может больше не использоваться, но вы может инициализировать его снова - указатель освобожден и больше не может быть инициализирован.

Знание этих шагов действительно важно. Когда вы работаете с типичным быстрым кодом, вы делаете все эти шаги, но они неявные. Возьмите этот простой пример:

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)
Другие вопросы по тегам