4

我正在使用 The Amazing Audio Engine 来处理 iOS 应用程序中的同步播放。

该框架要求您使用 C 函数作为在音频线程上调用的回调 (playbackTimingReceiver)。然后,您需要使用向其传递处理程序 (pageTurnHandler) 的 C 函数 (AEAudioControllerSendAsynchronousMessageToMainThread) 再次向主线程发送消息。

我在使用 C 时并没有过多的经验,但据我所知,我在消息中传递了一个需要取消引用的指针。

我可以通过以下方式成功实现:

PlaybackManager* receiver = *((PlaybackManager**)userInfo);

但只有当我在项目目标的已编译源中使用 -fno-objc-arc 标志为该文件关闭项目中的 ARC 时。

对于我的问题,是否可以在开启 ARC 的情况下实现这一点?如果是这样,正确的语法是什么?

相关代码段:

#pragma mark - Audio Timing Callback
-(AEAudioControllerTimingCallback)timingReceiverCallback
{
    return playbackTimingReceiver;
}

static void playbackTimingReceiver(PlaybackManager* receiver,
                                   AEAudioController *audioController,
                                   const AudioTimeStamp *time,
                                   UInt32 const frames,
                                   AEAudioTimingContext context)
{
    receiver->_hostTime = getUptimeInMilliseconds(time->mHostTime);
    AEAudioControllerSendAsynchronousMessageToMainThread(audioController,
                                                         pageTurnHandler,
                                                         &audioController,
                                                         sizeof(id));
}

static void pageTurnHandler(AEAudioController *audioController, void *userInfo, int userInfoLength)
{
    PlaybackManager* receiver = *((PlaybackManager**)userInfo);
    NSLog(@"Receiver:%@", receiver);
}
4

3 回答 3

2
PlaybackManager * receiver = (__bridge_transfer id)*(void **)userInfo;

应该做的伎俩。这首先将 转换userInfo为指向指针的指针,因为它包含原始对象指针的地址。取消引用以获取原始指针,并__bridge_transfer与类型一起使用——id或者PlaybackManager将工作——告诉 ARC 取消引用的值实际上是一个需要处理的对象。

于 2013-07-19T00:01:40.110 回答
1

如果不运行代码,似乎有两个错误:

1)您正在传递的内容audioController看起来像是要传递的内容receiver- 所以最后两个 argsAEAudioControllerSendAsynchronousMessageToMainThread应该是&receiver&sizeof(PlaykbackManager *)

2)您需要一个桥接来获取对象引用

就像是:

static void playbackTimingReceiver(PlaybackManager* receiver,
                                   AEAudioController *audioController,
                                   const AudioTimeStamp *time,
                                   UInt32 const frames,
                                   AEAudioTimingContext context)
{
    receiver->_hostTime = getUptimeInMilliseconds(time->mHostTime);
    AEAudioControllerSendAsynchronousMessageToMainThread(audioController,
                                                         pageTurnHandler,
                                                         &receiver,
                                                         sizeof(PlaybackManager*));
}

static void pageTurnHandler(AEAudioController *audioController, void *userInfo, int userInfoLength)
{
    PlaybackManager* receiver = (__bridge Playback *)*((PlaybackManager**)userInfo);
    NSLog(@"Receiver:%@", receiver);
}

注意:当将对象引用从 ARC 控制的世界传递到 C 世界时,您通常会在传入的过程中转移所有权 - 因此 ARC 不会释放引用的对象 - 并在返回的过程中将所有权转移回 - 因此 ARC 会恢复所有权管理。然而,由于AEAudioControllerSendAsynchronousMessageToMainThread, where的性质userInfo是通过地址传递并在内部复制 - 因此 size 参数,转移所有权更棘手。因此上面的代码没有。这意味着您必须通过拥有另一个所有者来确保任何对象receiver引用都保持活动状态。

于 2013-07-19T00:46:29.290 回答
0

您可以告诉 ARC 您想要的存储类型:

PlaybackManager *audioBufferPlayer = *(__weak PlaybackManager **)userInfo;

请务必在访问任何属性或调用任何方法之前进行必要的 nil 检查。

于 2016-12-13T07:58:49.303 回答