从 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++ 函数对待@property
s 的方式。当我尝试从 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 简单方法?
从服务器下载文件一直失败,但相同的 obj-c 代码在另一个环境和 IOS 应用程序中工作