从C++函数访问Obj-C属性(iOS)

Accessing an Obj-C property from a C++ function (iOS)

本文关键字:iOS 属性 Obj-C C++ 函数 访问      更新时间:2023-10-16

我正在编写一个iOS应用程序,该应用程序使用Core audio API在AppDelegate中进行一些音频处理。我的AppDelegate中有一个@property,它在ViewController中得到更新,这个@property需要在我的渲染回调函数中访问,该函数是用C++编写的。令我懊恼的是,我发现在C++函数中,不能像在Obj-C方法中那样简单地使用_propertyName来访问Obj-C @property,所以现在我想知道如何做到这一点。

这是我的@property,在AppDelegate.h:中

@property float centerFreq

这是我在AppDelegate.m:中的渲染回调函数

static OSStatus audioProcessingRenderCallback (
                                               void *                           inRefCon,
                                               AudioUnitRenderActionFlags * ioActionFlags,
                                               const AudioTimeStamp *           inTimeStamp,
                                               UInt32                           inBusNumber,
                                               UInt32                           inNumberFrames,
                                               AudioBufferList *                ioData
                                               ) {
    //audio processing stuff that needs to access _centerFreq
}

我的第一个想法是让audioProcessingRenderCallback成为一个Objective-C方法,但当我试图用以下代码将其设置为回调函数时,会导致一个错误:

AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = audioProcessingRenderCallback;

这个问题的最佳解决方案是什么?

正如我在对您的文章的评论中所描述的,一种方法是更改C++文件的扩展名。将扩展名设为.mm(即AudioProcessor.mm)。这将启用Objective-C++,然后您可以通过C++文件传递对象并对其进行调用。这可能是最简单的。

如果您不能更改C++文件的扩展名,那么您需要创建一个桥接函数。

在ViewController(.m文件)中,制作一个C函数,如下所示:

void updateCenterFreq( float value ) {
    myViewControllerInstance.centerFreq = value;
}

显然,您必须找到一种方法,使ViewController实例对C函数可见。一种方法是在.m文件中分配一个静态指针。只有当您有一个实例并且不担心线程时才有用,但这可能对您有用。如果视图控制器有多个实例,则必须找到查找该实例的方法。如何做到这一点超出了我在这里的回答范围。不过,我将对此进行修改,说如果您计划在非主线程上调用updateCenterFreq(),那么在设置centerFreq之前,您需要使用performSelectorOnMainThread进入主线程(我假设,由于它在视图控制器中,您计划更新UI,必须在主线程上完成)。

现在在AudioProcessor.h文件(C++文件的头)中执行:

extern "C" {
    void updateCenterFreq( float value );
}

然后您可以在需要时调用updateCenterFreq()。

同样,这不考虑线程安全,也不考虑如何定位实例,但这就是你可以做到的

您所需要做的就是将centerFreq的引用传递给您的方法:

static OSStatus audioProcessingRenderCallback (
                                               float *                          centerFrequency,
                                               void *                           inRefCon,
                                               AudioUnitRenderActionFlags * ioActionFlags,
                                               const AudioTimeStamp *           inTimeStamp,
                                               UInt32                           inBusNumber,
                                               UInt32                           inNumberFrames,
                                               AudioBufferList *                ioData
                                               ) {
    //audio processing stuff that needs to access _centerFreq
}

然后对该引用做你想做的事情,更新会反映在你的属性中。