我用Google搜索,我发现这个主题有一百万个结果。但这些页面都没有帮助我。我认为我有一个非常普遍的问题。我正在玩音频编程,特别是使用音频队列。我的程序的目的与解释问题无关。但简而言之:当我尝试从c ++代码调用objective-c函数时出现错误。所以这是包含错误的代码: AudioRecorder.h:
#import <Foundation/Foundation.h>
@interface AudioRecorder : NSObject {
}
-(void)setup;
-(void)startRecording;
-(void)endRecording;
-(void)playAlarmSound;
@end
这是实现:AudioRecorder.mm:
#import "AudioRecorder.h"
#include <AudioToolbox/AudioToolbox.h>
#include <iostream>
using namespace std;
@implementation AudioRecorder
static const int kNumberBuffers = 3;
...
static void HandleInputBuffer (void *aqData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime,
UInt32 inNumPackets,
const AudioStreamPacketDescription *inPacketDesc ) {
AQRecorderState *pAqData = (AQRecorderState *) aqData;
if (inNumPackets == 0 &&
pAqData->mDataFormat.mBytesPerPacket != 0)
inNumPackets =
inBuffer->mAudioDataByteSize / pAqData->mDataFormat.mBytesPerPacket;
UInt32 size;
AudioQueueGetPropertySize ( inAQ, kAudioQueueProperty_CurrentLevelMeter, &size );
char* levelMeterData = new char[size];
AudioQueueGetProperty ( inAQ, kAudioQueueProperty_CurrentLevelMeter, levelMeterData, &size );
AudioQueueLevelMeterState* meterState = reinterpret_cast<AudioQueueLevelMeterState*>(levelMeterData);
cout << "mAveragePower = " << meterState->mAveragePower << endl;
cout << "mPeakPower = " << meterState->mPeakPower << endl;
delete levelMeterData;
[self playAlarmSound]; //<--- here I get the error: Use of undeclared identifier 'self'
if (pAqData->mIsRunning == 0)
return;
AudioQueueEnqueueBuffer ( pAqData->mQueue, inBuffer, 0, NULL );
}
...
-(void)playAlarmSound {
NSLog(@"Alarmsound....");
}
当我省略“[self playAlarmSound];”一切正常。那么如何从我的C ++代码中调用这个Objective-C函数呢?
答案 0 :(得分:6)
self
仅存在于Objective-C方法中,并且是C样式函数。您需要在设置回调时将self
从Objective-C方法传递到inUserData,然后将其强制转换回正确的类型。
//This is an example for using AudioQueueNewInput
//Call this in an Objective-C method passing self to inUserData
AudioQueueNewInput (
const AudioStreamBasicDescription *inFormat,
AudioQueueInputCallback inCallbackProc,
// this is where you will pass (void*)self
void *inUserData,
CFRunLoopRef inCallbackRunLoop,
CFStringRef inCallbackRunLoopMode,
UInt32 inFlags,
AudioQueueRef *outAQ
);
和你原来的实现
static void HandleInputBuffer (void *aqData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime,
UInt32 inNumPackets,
const AudioStreamPacketDescription *inPacketDesc )
{
AudioRecorder *ar_instance = (AudioRecorder*)aqData;
...
[ar_instance playAlarmSound];
...
}
答案 1 :(得分:4)
这确实是一个常见问题。 self
在这里不起作用,因为这不是AudioRecorder
类的方法,不是因为它是Objective-C代码。您使用的是Objective-C ++文件,因此所有有效的Objective-C代码都可以使用。如果您对[anAudioRecorder playAlarmSound]
有很好的引用,那么anAudioRecorder
会正常工作。
那么,如果我们无法访问self
,我们如何获得参考?通常的方法是使用此函数的void* aqData
参数作为指向AudioRecorder
对象的指针。当您注册此回调时,您告诉它void*
参数是什么,在这种情况下是指向您的AQRecorderState
对象或结构的指针,您似乎无论如何都使用它。相反,您可以在注册时使用指向self
的指针,以便您可以在此处使用该对象。
另一种选择是使用共享的AudioRecorder
对象,在这种情况下,您可以调用[AudioRecorder sharedInstance]
(类,而不是实例,方法)来获取AudioRecorder
对象你要。因为这里的另一个答案详细阐述了第一种方法,下面是如何使用共享实例选项:向AudioRecorder
对象添加sharedInstance
的静态实例和类方法AudioRecorder
,如下所示:
static AudioRecorder* sharedMyInstance = nil;
+ (id) sharedInstance {
@synchronized(self) {
if( sharedMyInstance == nil )
sharedMyInstance = [[super allocWithZone:NULL] init];
}
return sharedMyInstance;
} // end sharedInstance()
然后,当您想要使用回调中的AudioRecorder
时,可以使用[AudioRecorder sharedInstance]
获取共享实例。如果只有一个AudioRecorder
,这是一个非常有用的范例 - 它消除了大量的引用传递。