【问题标题】:Create a Weak UnsafeMutableRawPointer创建一个弱 UnsafeMutableRawPointer
【发布时间】:2020-04-15 18:40:44
【问题描述】:

所以我尝试使用 CoreAudio 方法AUGraphAddRenderNotify(...),但我需要在通知块中创建此通知的类的引用。因为这是一个 C 函数,所以我不能简单地添加一个 [weak self] in 闭包捕获。查看Documentation,该方法的最后一个参数允许是UnsafeMutableRawPointer,它将在块执行期间作为第一个参数传入。在this suggestion 之后,这是我拥有的代码:

let selfPointer = Unmanaged.passUnretained(self).toOpaque()
AUGraphAddRenderNotify(graph, { (audioPlayerPointer, _, _, _, _, _) -> OSStatus in
    let audioPlayer = Unmanaged<AudioPlayer>.fromOpaque(audioPlayerPointer).takeUnretainedValue()
    ...

    return noErr
}, selfPointer)

这是我的问题: 我需要弄清楚如何安全地获取该指针背后的值(占零)。更具体地说,我想安全地访问 audioPlayer 并确保在我使用它时它还没有被释放。目前,一切正常,直到 audioPlayer 被释放,然后我的应用程序崩溃。我知道我可以使用AUGraphRemoveRenderNotify(...) 在对象被释放之前停止通知,但不幸的是这种方法不是我想要的。如何检查指针指向的对象是否已经被释放?

提前致谢!

【问题讨论】:

  • 在播放器的 deinit 方法中调用 AUGraphRemoveRenderNotify 是一个干净的解决方案,你为什么不喜欢呢? – 另一种方法是创建一个 retained 指针。这可以防止播放器在您明确释放之前被释放。
  • 我不在 deinit 方法中这样做的原因是因为块中的一些代码在主线程上运行,并且可能会在 AudioPlayer 已经被释放后尝试访问它
  • 我不完全确定我是否理解您的意思。一旦通知程序被删除,回调块中的代码就不能被调用。如果你在回调 inside 调度异步代码,那么你可以在那里创建一个弱引用。 – 也许更多一些代码来演示这个问题会有所帮助。

标签: ios swift pointers core-audio raw-pointer


【解决方案1】:

弱引用实际上并不是这样工作的

有趣的是,弱引用实际上并不指向它们建模的目标对象。它们指向边表,其生命周期与目标对象不同。

  • 在对对象进行第一次弱引用时分配一个边表条目。
  • 每个弱引用的创建都会增加边表条目的引用计数,而弱引用的每次销毁都会减少它。
  • 一旦目标对象被解除分配,边表条目将保留在原处。这样一来,所有弱引用都不会变成悬空指针。
  • 在最终释放目标对象后,所有访问弱引用(现已死)的尝试都会导致弱引用被nil-ed 输出(这是您作为用户观察到的),但是还减少了侧表条目
  • 因此,每个弱引用要么需要被销毁(例如超出范围),要么在边表条目过期之前尝试被访问。

由于这些边表条目没有暴露给“用户空间”Swift 代码,因此您无法创建指向它们的原始指针,因此您无法真正以这种方式处理弱引用。

其他想法

我有一些关于你可以做什么的想法,虽然我没有尝试过。

  1. 您可以利用UnsafeMutableRawPointer 指针传入Weak&lt;T&gt; 包装器,例如:

    struct Weak<T: AnyObject> {
        wear var object: T?
    }
    

虽然我认为在这种情况下它必须是class

  1. 或用于其他一些机制,例如传入闭包(弱捕获对象)

【讨论】:

  • 是的,您需要一个类来“隧道”指向 C 函数的指针。你必须保留对它的引用。如果那是某个类的实例属性,那么你又会遇到同样的问题,除非我弄错了。
  • 我尝试使用第一个想法并使用 UnsafeMutableRawPointer.allocate() 创建一个指针,但在 AudioPlayer 被释放后我尝试执行 if let audioPlayer = weakWrapper.object as? AudioPlayer 我得到 AURemoteIO::IOThread (11): EXC_BAD_ACCESS (code=1, address=0xeeba0dde2a60)
  • @CentrumGuy 你能发布一个最小的可编译示例吗?你可以创建一个虚拟函数来代替AUGraphAddRenderNotify,它只需要一个@convention(c) (UnsafeMutableRawPointer) -&gt; Void
  • 是的,我现在就这样做
  • 抱歉拖了这么久。在我的示例中,我无法让我的 AUGraph 生成通知回调,因为在我的实际项目中我使用的是音频流。尽管如此,这里是代码(假设我可以让 AUGraph 生成通知):gist.github.com/CentrumGuy/0fda355d7af25073d11778d61d9caf2f
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-29
  • 1970-01-01
  • 1970-01-01
  • 2012-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多