Ok, I did some more work on it and thought I had solved it, but unfortunately I haven’t.
Essentially the idea was to get hold of the CoronaRuntime in the “Open” method of the PluginLibrary, then store this for later use.
In the following example code I use a singleton to store the CoronaRuntime, and use the singleton in the blocks to grab the runtime.
But unfortunately this does not work either. I have provided screenshots of the line and error. They are EXC_BAD_ACCESS and SIGABRT.
Example 1:
Example 2:
It also throws errors in the Corona Runtime such as “tired to concatenate string” when I get the message back from Objective-C and manipulate it.
It’s also almost like the event is corrupting other parts of the Lua Stack. Is that possible?
Here is the code:
MyHelper.h
#import \<Foundation/Foundation.h\> #include "CoronaRuntime.h" #import \<UIKit/UIKit.h\> @interface MyHelper : NSObject { } @property ( nonatomic, retain ) id\<CoronaRuntime\> coronaRuntime; + (id)getSingleton; - (NSString \*)getCoronaDocumentsPath; - (void)imageSavedToCameraRoll:(UIImage \*)image didFinishSavingWithError:(NSError \*)error contextInfo:(NSArray \*)contextInfo; @end
MyHelper.mm
#import "MyHelper.h" #import "CoronaLua.h" #import "CoronaRuntime.h" @implementation MyHelper { } @synthesize coronaRuntime; + (id)getSingleton { static MyHelper \* sharedInstance = nil; static dispatch\_once\_t onceToken; dispatch\_once( &onceToken, ^{ sharedInstance = [[self alloc] init ]; }); return sharedInstance; } - (id)init { if ( self = [super init] ) { // init variables here } return self; } - (NSString \*)getCoronaDocumentsPath { NSArray \* paths = NSSearchPathForDirectoriesInDomains( NSLibraryDirectory, NSUserDomainMask, YES ); NSString \* rootPath = paths[0]; NSString \* coronaDocumentsPath = [rootPath stringByDeletingLastPathComponent]; coronaDocumentsPath = [coronaDocumentsPath stringByAppendingPathComponent:@"Documents"]; return coronaDocumentsPath; } - (void)imageSavedToCameraRoll:(UIImage \*)image didFinishSavingWithError:(NSError \*)error contextInfo:(NSArray \*)contextInfo { NSString \*message; NSString \*title; if (!error) { // success // grab the success completion block from the array void (^ successBlock)() = [contextInfo objectAtIndex:0]; successBlock(); } else { // error // grab the error completion block from the array void (^ errorBlock)() = [contextInfo objectAtIndex:1]; errorBlock(); } } @end
PluginLibrary.h
#ifndef \_PluginLibrary\_H\_\_ #define \_PluginLibrary\_H\_\_ #include "CoronaLua.h" #include "CoronaMacros.h" // This corresponds to the name of the library, e.g. [Lua] require "plugin.library" // where the '.' is replaced with '\_' CORONA\_EXPORT int luaopen\_plugin\_testplugin( lua\_State \*L ); #endif // \_PluginLibrary\_H\_\_
PluginLibrary.mm
#import "PluginLibrary.h" #include "CoronaRuntime.h" #import \<UIKit/UIKit.h\> #include "MyHelper.h" // ---------------------------------------------------------------------------- class PluginLibrary { public: typedef PluginLibrary Self; public: static const char kName[]; static const char kEvent[]; protected: PluginLibrary(); public: bool Initialize( CoronaLuaRef listener ); public: CoronaLuaRef GetListener() const { return fListener; } public: static int Open( lua\_State \*L ); protected: static int Finalizer( lua\_State \*L ); public: static Self \*ToLibrary( lua\_State \*L ); public: static int init( lua\_State \*L ); static int moveImageToCameraRoll( lua\_State \*L ); private: CoronaLuaRef fListener; }; // ---------------------------------------------------------------------------- // This corresponds to the name of the library, e.g. [Lua] require "plugin.library" const char PluginLibrary::kName[] = "plugin.testplugin"; // This corresponds to the event name, e.g. [Lua] event.name const char PluginLibrary::kEvent[] = "TestPlugin"; PluginLibrary::PluginLibrary() : fListener( NULL ) { } bool PluginLibrary::Initialize( CoronaLuaRef listener ) { // Can only initialize listener once bool result = ( NULL == fListener ); if ( result ) { fListener = listener; } return result; } int PluginLibrary::Open( lua\_State \*L ) { // =================================== // ! Important code ! // get shared instance of the singleton MyHelper \* helper = [MyHelper getSingleton]; // get the corona runtime void \* platformContext = CoronaLuaGetContext( L ); // now store the corona runtime in the singleton [helper setCoronaRuntime:(id\<CoronaRuntime\>)platformContext]; // =================================== // Register \_\_gc callback const char kMetatableName[] = \_\_FILE\_\_; // Globally unique string to prevent collision CoronaLuaInitializeGCMetatable( L, kMetatableName, Finalizer ); // Functions in library const luaL\_Reg kVTable[] = { { "init", init }, { "moveImageToCameraRoll", moveImageToCameraRoll }, { NULL, NULL } }; // Set library as upvalue for each library function Self \*library = new Self; CoronaLuaPushUserdata( L, library, kMetatableName ); luaL\_openlib( L, kName, kVTable, 1 ); // leave "library" on top of stack return 1; } int PluginLibrary::Finalizer( lua\_State \*L ) { Self \*library = (Self \*)CoronaLuaToUserdata( L, 1 ); CoronaLuaDeleteRef( L, library-\>GetListener() ); delete library; return 0; } PluginLibrary \* PluginLibrary::ToLibrary( lua\_State \*L ) { // library is pushed as part of the closure Self \*library = (Self \*)CoronaLuaToUserdata( L, lua\_upvalueindex( 1 ) ); return library; } // [Lua] library.init( listener ) int PluginLibrary::init( lua\_State \*L ) { int listenerIndex = 1; if ( CoronaLuaIsListener( L, listenerIndex, kEvent ) ) { Self \*library = ToLibrary( L ); CoronaLuaRef listener = CoronaLuaNewRef( L, listenerIndex ); library-\>Initialize( listener ); } return 0; } int PluginLibrary::moveImageToCameraRoll( lua\_State \*L ) { // my singleton helper instance MyHelper \* helper = [MyHelper getSingleton]; // get the corona documents path NSString \* filePath = [helper getCoronaDocumentsPath]; // append the filename of the file provided by the calling lua function filePath = [filePath stringByAppendingPathComponent:[ NSString stringWithUTF8String:lua\_tostring( L, -1 )] ]; Self \* library = ToLibrary( L ); // completion block to be called if the image is saved correctly void (^moveFileCompletionBlock)(void) = ^{ // notice we are not using the param L, we are // creating our own reference to the lua\_State // from our CoronaRuntime stored in the singleton MyHelper \* helper = [MyHelper getSingleton]; id\<CoronaRuntime\> runtime = [helper coronaRuntime]; lua\_State \* state = runtime.L; NSString \* finishedMessage = @"Event:FinishedMovingFile"; CoronaLuaNewEvent( state, kEvent ); lua\_pushstring( state, [finishedMessage UTF8String] ); lua\_setfield( state, -2, "message" ); CoronaLuaDispatchEvent( state, library-\>GetListener(), 0 ); }; // completion block to be called if the image is NOT saved correctly void (^moveFileErrorBlock)(void) = ^{ MyHelper \* helper = [MyHelper getSingleton]; id\<CoronaRuntime\> runtime = [helper coronaRuntime]; lua\_State \* state = runtime.L; NSString \* finishedMessage = @"Event:ErrorMovingFile"; CoronaLuaNewEvent( state, kEvent ); lua\_pushstring( state, [finishedMessage UTF8String] ); lua\_setfield( state, -2, "message" ); CoronaLuaDispatchEvent( state, library-\>GetListener(), 0 ); }; // store the completion blocks in array NSArray \* blocks = [[ NSArray alloc] initWithObjects:moveFileCompletionBlock, moveFileErrorBlock, nil]; // load image UIImage \* image = [UIImage imageNamed:filePath]; // save image to camera roll, pass the blocks to the helper object UIImageWriteToSavedPhotosAlbum(image, helper, @selector(imageSavedToCameraRoll: didFinishSavingWithError: contextInfo:), blocks); return 0; } // ---------------------------------------------------------------------------- CORONA\_EXPORT int luaopen\_plugin\_testplugin( lua\_State \*L ) { return PluginLibrary::Open( L ); }