Audioshare functionality for iOS apps

Here’s a pattern I recently learned for integrating objectiveC stuff so it appears like regular JUCE classes, via the Listener pattern:

//Foo.h
struct Foo
{
    Foo();
    enum NativeAction
    {
        a, b, c, //etc
    };
    void handleNativeAction(NativeAction nativeAction);
    struct Listener
    {
         virtual ~Listener() { }
         virtual void nativeActionCallback(Foo*, NativeAction&) = 0;       
    };
    Array<Listener*> listeners;
    void addListener( Listener* L ) { listeners.addIfNotAlreadyThere( L ); }
    void removeListener( Listener* L ) { listeners.removeFirstMatching( L ); }
    //don't forget your listener locks!
};
//Foo.mm file
#include "Foo.h"
#import //CoreFoundations.h or UIKit or whatever

@interface MyObjCWrapper : NSObject
{
    Foo* myFoo;
    //other data members
};
//member functions of MyObjCWrapper
-(id) init;
-(void) setOwner:(Foo*)owner;
-(void) someCallback:(ArgType)args;
@end
@implementation MyObjCWrapper
-(id)init 
{ 
    if( self = [super init] )
    {
         //do all of the setup into native iOS calls here so 
         //someCallback gets called when the native callbacks are triggered
    }
    return self;
}
-(void) setOwner:(Foo*)owner
{
    myFoo = owner;
}
-void someCallback:(ArgType)args
{
    //convert args to Foo::NativeAction
    Foo::NativeAction fooArg = convert(args); 
    myFoo->handleNativeAction(fooArg); //pass it to Foo instance
}
@end 
//Foo implementation
Foo::Foo()
{
    //I'm not sure how this doesn't leak.  
    //it probably doesn't matter on iOS, tbh because Apple just hard-crashes 
    //apps when memory is needed.
    //maybe Foo needs a destructor to release this properly? 
    MyObjCWrapper* wrapper = [[MyObjCWrapper alloc] init];
    [wrapper setOwner:this];
}

void Foo::handleNativeAction(NativeAction someParam)
{
    //now your objC result has been passed to pure C++
    for( auto* listener : listeners )
        listener->nativeActionCallback(this, someParam);
}

Just add a Foo member to your class, and register your class as a Foo::Listener

struct MyClass : public Foo::Listener
{
    void nativeActionCallback(Foo*, Foo::NativeAction& action) override 
    {
        //tadah, your ObjC results get passed to JUCE here.
    }
    Foo foo;

    MyClass() { foo.addListener(this); }
};

I’m not sure if that answers your question, but you can probably use this to wrap that openURL objectiveC function into a JUCE listener-based class.

2 Likes