Properly use Objective C++

后端 未结 2 703
暖寄归人
暖寄归人 2021-02-03 16:31

I\'m coding an app for iOS and I recently #included a C++ header file in an Objective C implementation (.m) file. I changed the extension from .m to .mm and expected everything

相关标签:
2条回答
  • 2021-02-03 16:50

    Unfortunately, if you just start making classes .mm, any class that uses that .mm's header will also need to become .mm. If you continue to just change your class extensions, you will eventually make the whole project Objective-c++. If that is your intention, then you can just change your build settings to compile for Objective-c++ (which could be a house of pain for you).

    However, if you use some header magic, you will avoid a lot of hassle. Just make sure to change your Compile sources as build property to According to file type before compiling.

    Here's something I did with a wrapper class I wrote to isolate a c++ class from the rest of my Objective-c classes. The c++ class is MyClass.

    MyClassWrapper.h

    //declare c++ impl for Obj-C++
    #ifdef __cplusplus
    class CppPlanterModel;
    namespace com{namespace company{namespace mypackage {class MyClass;}}}
    typedef com::company::mypackage::MyClass CppMyClass;
    #endif
    
    //declare obj-c impl
    #ifdef __OBJC__
    #ifndef __cplusplus
    typedef void CppMyClass;
    #endif
    #endif
    
    @interface MyClassWrapper : NSObject {
        CppMyClass* _myClass;
    }
    //etc etc
    @end
    

    MyClassWrapper.mm

    #include "MyClass.h"
    using namespace com:company:mypackage;
    
    class CppMyClass : public MyClass {
        CppMyClass() {};
        ~CppMyClass() {};
        //other stuff you might like to have
    };
    
    @implementation MyClassWrapper
        //etc etc
    @end
    

    Here's another thing I did with a different header to handle sharing extern stuff:

    Something.h

    #ifdef __cplusplus
    #define FV_EXTERN       extern "C" __attribute__((visibility ("default")))
    #else
    #define FV_EXTERN       extern __attribute__((visibility ("default")))
    #endif
    
    FV_EXTERN const int kMyInt;
    FV_EXTERN int GetAnotherInt(...);
    

    I recommend reading this blog entry about wrapping c++ (which also has links to other blog entries of a similar topic): http://robnapier.net/blog/wrapping-c-take-2-1-486

    0 讨论(0)
  • 2021-02-03 16:56

    following the code at Rob Napier's blog I did it for CAAudioUnitOutputCapturer. Thought I would share it to save other folks time.

    RNWrap.h

    //
    //  RNWrap.h
    //
    //  ObjC wrapper for Wrap.cpp
    //
    
    #import <Foundation/Foundation.h>
    #import <CoreFoundation/CoreFoundation.h>
    #import <AudioUnit/AudioUnit.h>
    #import <AudioToolbox/AudioToolbox.h>
    #import <AVFoundation/AVFoundation.h>
    #import <CoreAudio/CoreAudioTypes.h>
    
    struct RNWrapOpaque;
    
    @interface RNWrap : NSObject {
    struct RNWrapOpaque *_cpp;
    }
    
    - (id) initWithAudioUnit:(AudioUnit) au andURL:(CFURLRef) outputFileURL andAudioFileTypeID:(AudioFileTypeID) fileType andAudioStreamBasicDescription: (const AudioStreamBasicDescription) asbd;
    - (void) Start;
    - (void) Close;
    - (void) Stop;
    
    @end
    

    RNWrap.mm

    //
    //  RNWrap.mm
    //  Objective C++ Wrapper Class for CAAudioUnitOutputCapturer.h
    //
    //  Created by Pier 23/10/12
    //  Copyright 2012 DreamUpApps. All rights reserved.
    //
    
    #import "RNWrap.h"
    #import "CAAudioUnitOutputCapturer.h"
    
    @interface RNWrap ()
    @property (nonatomic, readwrite, assign) RNWrapOpaque *cpp;
    @end
    
    @implementation RNWrap
    @synthesize cpp = _cpp;
    
    struct RNWrapOpaque
    {
    public:
        RNWrapOpaque(AudioUnit au, CFURLRef outputFileURL, AudioFileTypeID fileType, const AudioStreamBasicDescription format) : outputCapturer(au, outputFileURL, fileType,  format, 0) {}; // note added bus number = 0 at the end
    CAAudioUnitOutputCapturer outputCapturer;
    };
    
    - (id)initWithAudioUnit:(AudioUnit) au andURL:(CFURLRef) outputFileURL andAudioFileTypeID:(AudioFileTypeID) fileType andAudioStreamBasicDescription: (const AudioStreamBasicDescription) format
    {
    self = [super init];
    if (self != nil)
    {
        self.cpp = new RNWrapOpaque(au, outputFileURL, fileType, format);
    }
    return self;
    }
    
    - (void)dealloc
    {
    delete _cpp;
    _cpp = NULL;
    
    //[super dealloc];
    }
    
    - (void) Start
    {
    self.cpp->outputCapturer.Start();
    }
    
    - (void) Stop
    {
    self.cpp->outputCapturer.Stop();
    }
    
    - (void) Close
    {
    self.cpp->outputCapturer.Close();
    }
    
    @end
    

    You use it like this in your class.

    - (void) captureInAppAudio:(AudioUnit) auToCapture
    {
    AudioStreamBasicDescription destFormat; 
    memset( &destFormat, 0, sizeof(AudioStreamBasicDescription) );
    destFormat.mSampleRate = 44100;
    destFormat.mFormatID = kAudioFormatLinearPCM;
    destFormat.mFormatFlags = ( kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagIsBigEndian );
    destFormat.mBytesPerPacket = 2;
    destFormat.mFramesPerPacket = 1;
    destFormat.mBytesPerFrame = 2;
    destFormat.mChannelsPerFrame = 1;
    destFormat.mBitsPerChannel = 16;
    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    
    soundPath = [documentsDirectory stringByAppendingString:@"/recording.caf"] ;
    CFURLRef fileurl = CFURLCreateWithFileSystemPath(NULL, (CFStringRef)soundPath, kCFURLPOSIXPathStyle, false);
    captor = [[RNWrap alloc] initWithAudioUnit:auToCapture andURL:fileurl andAudioFileTypeID:'caff' andAudioStreamBasicDescription:destFormat];
    
    [captor Start];
    }
    

    Hope this helps someone else out there!

    Pier.

    0 讨论(0)
提交回复
热议问题