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

Posted

技术标签:

【中文标题】从 C++ 函数访问 Obj-C 属性 (iOS)【英文标题】:Accessing an Obj-C property from a C++ function (iOS) 【发布时间】:2014-09-07 03:44:56 【问题描述】:

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

这是我在 AppDelegate.h 中的@property

@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 吗?然后它将编译为 Objective-C++,您可以像在 .m 文件中一样访问它。不是答案,因为我没有解决您的“如何访问价值”问题,但您可能会发现这种方法很有用。 感谢您的建议,但这似乎并没有改变我的 C++ 函数对待@propertys 的方式。当我尝试从 C++ 函数中访问它们时,它们仍然无法识别。 将 C++ 文件扩展名更改为 .mm 后,从 C++ 文件中包含 ViewController.h。在您的 ViewController 上放置一个方法,例如 -(ViewController*) getInstance;将实例(或通过其他机制使其可访问)返回到 C++ 文件。然后在 C++ (.mm) 文件中,你可以调用 instance.centerFreq = 1.0;但是,请注意,您只能在主线程上执行此操作。请参阅下面的答案。 【参考方案1】:

正如我在对您的帖子的评论中所描述的,一种方法是更改​​ 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()。

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

【讨论】:

就像我之前提到的,将文件从 .m 更改为 .mm 似乎对我从 C++ 代码访问属性的能力没有任何影响。至于你的其他建议,我有点困惑。 centerFreq 是 AppDelegate 的属性,而不是 ViewController。但是,我在 ViewController 中有一些我希望能够更新 centerFreq 的东西,所以我现在拥有的是:appDel = ((PWAppDelegate *)[[UIApplication sharedApplication] delegate]);appDel.centerFreq = [self updateFreq:param1 withPar:param2]; oof,对于评论中令人讨厌的代码格式感到抱歉。 对不起。将我所说的“View Controller”替换为“App Delegate”。如果您不使用 .mm 文件,关键是在 AppDelegate .m 文件中创建一个纯 C 函数访问器,然后在 C++ 文件中将该函数声明为 extern "C",然后从 C++ 文件中调用它. .m 文件中的纯 C 函数可以调用 Objective-C 函数。同样,如果您将 .cpp 文件重命名为 .mm,您可以在本机调用所有 Objective-C 函数,只要您在 C++ 文件中包含正确的头文件。 将.cpp 文件重命名为.mm,然后在其中#include <Cocoa/Cocoa.h>#include "PWAppDelegate.h"。然后你可以做((PWAppDelegate *) [[UIApplication sharedApplication] delegate]).centerFreq = 1.0; 抱歉,我可能不太清楚。 ((PWAppDelegate *) [[UIApplication sharedApplication] delegate]).centerFreq = 1.0; 在我的 ViewController.mm 中,它(似乎)工作得很好。没有 .cpp 文件,但我在我的 AppDelegate.m 中编写 C++ 代码,我试图从中访问在 AppDelegate.h 中声明的 centerFreq 属性。就目前而言,centerFreq 应该由 ViewController 中的行更新,但我无法在 AppDelegate.m 中访问它以找出答案。这更有意义吗?还是我误会了你?【参考方案2】:

您需要做的就是将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

然后在该参考上做你想做的事情,更新将反映在你的财产中。

【讨论】:

这是一个非常糟糕的主意。 centerFreq 应该被认为是一个私有类成员,它的设置器可能会被覆盖或具有完全绕过的副作用。 +1 分,请在使用上述答案之前参考par的评论

以上是关于从 C++ 函数访问 Obj-C 属性 (iOS)的主要内容,如果未能解决你的问题,请参考以下文章

从具有属性的 NSObject 转换为 NSDictionary 的 Obj-C 简单方法?

C++ 派生类访问属性

在 obj-c/C++ 中使用 UDP 的示例?

从服务器下载文件一直失败,但相同的 obj-c 代码在另一个环境和 IOS 应用程序中工作

iOS:在 UIWebview 中使用 javascript 调用 obj-c 方法

Obj-C - 添加“跳过备份”属性总是失败