Swift получить значение от UnsafeMutablePointer с помощью UnsafePointer


Я пытаюсь передать contextInfo типаUnsafeMutablePointer<Void> в UISaveVideoAtPathToSavedPhotosAlbum и использовать его в функции обратного вызова. По какой-то причине я не могу получить доступ к contextInfo в виде строки, используя UnsafePointer<String>(x).memory, Когда я нахожусь в функции обратного вызова.

Я почти уверен, что это что-то простое, чего мне не хватает, но я потратил много часов, пытаясь понять это.

Ниже приведен некоторый код, который я попробовал.

Работает следующий код.

var testStr:String = "hello"
takesAMutableVoidPointer(&testStr)

func takesAMutableVoidPointer(x: UnsafeMutablePointer<Void>){
    var pStr:String = UnsafePointer<String>(x).memory
    println("x = (x)")
    println("pStr = (pStr)")
}

Однако следующий код этого не делает работа.

var testStr:String = "hello"

if UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(filePath){ //the filePath is compatible
    println("Compatible")
    //UISaveVideoAtPathToSavedPhotosAlbum(filePath, self, nil, nil)
    UISaveVideoAtPathToSavedPhotosAlbum(filePath, self, "video:didFinishSavingWithError:contextInfo:", &testStr)
}
else{
    println("Not Compatible")
}

func video(video: NSString, didFinishSavingWithError error:NSError, contextInfo:UnsafeMutablePointer<Void>){
    var pStr:String = UnsafePointer<String>(contextInfo).memory
    println("contextInfo = (contextInfo)")
    println("pStr = (pStr)")
}

Как только я доберусь до следующей строки:

var pStr:String = UnsafePointer<String>(contextInfo).memory

Я продолжаю получать следующую ошибку:

Thread 1: EXC_BAD_ACCESS(code=1, address=0x0)
Любая помощь в этом была бы очень признательна.

Спасибо.

Обновить

Ринтаро прокомментировал, что testStr должен быть верхнего уровня, но следующий код работает.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        var testStr:String = "hello"
        takesAMutableVoidPointer(&testStr)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func takesAMutableVoidPointer(x: UnsafeMutablePointer<Void>){
        var answer = UnsafePointer<String>(x).memory
        println("x = (x)")
        println("answer = (answer)")
    }
}
Я стараюсь не использовать глобальные переменные без крайней необходимости. Возможно, мне придется это сделать, но поскольку я могу выполнить приведенный выше код, похоже, что я это делаю. не нужно использовать глобальную переменную.
1 6

1 ответ:

Как обсуждалось в комментариях OP, testStr уже освобожден.

Существует ли какой-либо способ принудительно сохранить переменную, которая была создана в функции? Тогда отпустите его позже?
Это не невозможно, но я не знаю, что это лучший способ сделать это.

В любом случае, попробуйте сделать это с помощью шаблона Playground или OS X "инструмент командной строки":

import Foundation

func foo() {
    var str:NSString = "Hello World"
    let ptr = UnsafePointer<Void>(Unmanaged<NSString>.passRetained(str).toOpaque())
    bar(ptr)
}

func bar(v:UnsafePointer<Void>) {
    let at = dispatch_time(
        DISPATCH_TIME_NOW,
        Int64(2.0 * Double(NSEC_PER_SEC))
    )
    dispatch_after(at, dispatch_get_main_queue()) {
        baz(v)
    }
}

func baz(v:UnsafePointer<Void>) {
    println("notified")
    let str = Unmanaged<NSString>.fromOpaque(COpaquePointer(v)).takeRetainedValue()
    println("info: \(str)")
}


foo()

println("started")

dispatch_main()
  • Unmanaged<NSString>.passRetained(str) увеличивает число удержаний.
  • Unmanaged<NSString>.fromOpaque(...).takeRetainedValue() уменьшает его и извлекает объект.

Я думаю, что использование чистого Swift String невозможно. потому что String является struct и выделяется в стековой памяти. Может быть, буфер его расположен в куче, но мы не можем получить к нему прямой доступ.