簡體   English   中英

從C ++代碼調用Objective C函數

[英]Calling a Objective C function from C++ Code

我搜索了一下,我發現這個主題有一百萬個結果。 但這些頁面都沒有幫助我。 我認為我有一個非常普遍的問題。 我正在玩音頻編程,特別是使用音頻隊列。 我的程序的目的與解釋問題無關。 但簡而言之:當我嘗試從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函數呢?

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];
    ...
}

這確實是一個普遍的問題。 self在這里不起作用,因為這不是AudioRecorder類的方法,不是因為它是Objective-C代碼。 您使用的是Objective-C ++文件,因此所有有效的Objective-C代碼都可以使用。 [anAudioRecorder playAlarmSound]可以正常工作,前提是您對anAudioRecorder有很好的引用。

那么如果我們無法訪問self我們如何獲得參考? 通常的方法是使用此函數的void* aqData參數作為指向AudioRecorder對象的指針。 當您注冊此回調時,您告訴它void*參數是什么,在這種情況下是指向您的AQRecorderState對象或結構的指針,您似乎無論如何都不會使用它。 相反,您可以在注冊時使用指向self的指針,以便您可以在此處使用該對象。

另一種選擇是使用共享的AudioRecorder對象,在這種情況下,您可以調用[AudioRecorder sharedInstance] (類,而不是實例,方法)來獲取所需的AudioRecorder對象。 因為這里的另一個答案詳細闡述了第一種方法,下面是如何使用共享實例選項:將AudioRecorder的靜態實例和類方法sharedInstanceAudioRecorder對象,如下所示:

static AudioRecorder* sharedMyInstance = nil;

+ (id) sharedInstance {
    @synchronized(self) {
        if( sharedMyInstance == nil )
            sharedMyInstance = [[super allocWithZone:NULL] init];
    }
    return sharedMyInstance;
} // end sharedInstance()

然后,當您想要從回調中使用AudioRecorder ,可以使用[AudioRecorder sharedInstance]獲取共享實例。 如果只有一個AudioRecorder這是一個非常有用的范例 - 它消除了大量的引用傳遞。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM