通过UnsafeMutablePointer类型

时间:2018-01-15 03:26:46

标签: objective-c swift

我在Objective-C遇到了一种不熟悉的初始化模式,我正在努力在Swift中复制。

目标C

在示例代码中,他们定义了一个C结构,例如this(缩写为原始here):

struct AQPlayerState {
  AudioFileID mAudioFile;
}

以下是使用AQPlayerState的示例:

AQPlayerState aqData; // 1
OSStattus result = 
  AudioFileOpenURL(
    audioFileURL,
    fsRdPerm,
    0,
    &aqData.mAudioFile // 2
  );

上面的关键点是,aqData目前有未初始化的属性,AudioFileOpenURL代表它正在初始化aqData.mAudioFile

夫特

我试图在Swift中复制这种行为。这是我到目前为止所尝试的内容:

模型:

class Person {
  var name: String 

  init(name: String) {
    self.name = name
  }
}

class Foo {
  var person: Person?
}

我的想法是通过将Foo.person的引用传递给一个将代表它实例化的函数来复制Objective-C代码。

初始化功能:

func initializeWithBob(_ ptr: UnsafeMutablePointer<Person?>) {
  ptr.pointee = Person(name: "Bob")
}

initializeWithBob获取指向Person?类型地址的指针,并使用Person(name: "Bob")对象对其进行初始化。

这是我的测试代码:

let foo = Foo()
let ptr = UnsafeMutablePointer<Person?>.allocate(capacity: 1)
ptr.initialize(to: foo.person)
defer {
  ptr.deinitialize()
  ptr.deallocate(capacity: 1)
}

initializeWithBob(ptr)
print(foo.person) // outputs nil

initializeWithBob未能&#34;安装&#34;我的Person实例中的Foo类型的实例。我认为我的一些假设是错误的。寻求帮助纠正我的假设和对这种情况的理解。

提前致谢!

3 个答案:

答案 0 :(得分:1)

您可以通过withUnsafeMutablePointer(to:_:)来实现您的目标:

let foo = Foo()

withUnsafeMutablePointer(to: &foo.person) { (ptr) -> Void in
    initializeWithBob(ptr)
}

print(foo.person!.name) // outputs Bob

但是,我不推荐这种方法。恕我直言,将你正在使用的API包装在一个C函数中是更有意义的,你可以从Swift调用“很好”。您当前的方法存在的问题是,Swift开发人员难以阅读此类Swift,而且Audio Toolbox开发人员也很难阅读。

答案 1 :(得分:0)

@kelvinlau这是你想要实现的目标吗?

func initializeWithBob(_ ptr: UnsafeMutablePointer<Foo>) {
    ptr.pointee.person = Person(name: "Bob")
}

let foo = Foo()
let ptr = UnsafeMutablePointer<Foo>.allocate(capacity: 1)
ptr.initialize(to: foo)

initializeWithBob(ptr)
print(foo.person?.name ?? "nil")
ptr.deinitialize()
ptr.deallocate(capacity: 1)
print(foo.person?.name ?? "nil")

答案 2 :(得分:0)

Objective-C中的代码模式是 out参数,即返回值的参数,或 in out parameters ,这两个参数都通过一个值并返回一个。 Objective-C不直接支持这些,因此指针用于产生语义。

Swift在函数声明中有关键字inout指示的 in 参数。在函数内,对inout参数的赋值有效地为作为参数传递的变量赋值。在函数调用站点,变量必须以&作为前缀,以表明它本身就是变量,而不是有效传递的值。

保持您的PersonFoo与您的职能相同:

func initializeWithBob(_ ptr: inout Person?)
{
   ptr = Person(name: "Bob")
}

可以使用它,例如:

var example = Foo()
initializeWithBob(&example.person)

在Swift中使用inout比尝试使用指针构建相同的语义要好。

HTH

注意除非您好奇,否则可以跳过此

&#34;有效&#34;曾经使用过几次。通常 out 参数由参数传递方法按结果调用实现,而 in out 使用按值调用 - 结果。使用这些方法之一,返回的值仅分配给函数返回的传递变量。

另一个参数传递方法是按引用调用,它类似于按值调用 之外的每个和函数内的每个参数赋值都会立即传递给变量。这意味着在函数返回之前,对传递的变量的更改可能是

Swift by design没有指定其inout是使用按值调用还是使用call-by引用。因此,而不是在答案中指定确切的语义,并且有效地&#34;使用。