Export a Custom ObjC Class to Perl?

  • So, I've been able to load Perl modules, execute code, export an NSDictionary of strings as a Perl hash and get at it, and so on.  All this is great!  CamelBones is a wonderful tool in that respect.

    However, I'm having a heck of a time trying to export a custom ObjC object into Perl; I'm using CamelBones to embed Perl scripting into my app, and in order to do this, I need a little 'bridge' object that provides a few useful methods to allow the scripts to inject information back in and drive the app.  No problem on designing those... but when I take my little NSObject subclass with these handy methods, and use setValue:forKey: on the sharedPerl object... it goes blooie.  EXC_BAD_ACCESS somewhere deep in the bowels of the Perl library, to be precise.

    In an effort to track down what was going wrong, I tried making an NSObject, and exporting it, and that worked fine.  And then I tried making a subclass of NSObject with absolutely no changes -- just a simple subclass -- and exporting it into the Perl environment, and again, kerblooie.

    Am I missing something?  Am I hosed because I'm on an Intel MacBook Pro?  Haaaalp. :)

    • Ha!  After a bit more poking about in the source, I found the CBWrapObjectiveCClass() call, and realized I had to call that before I used that class in setValue:forKey:

      Now it all works like a charm.  Thanks for a great framework! :)

      • Sherm Pendley
        Sherm Pendley

        That's odd - that method's should be called automatically for all Objective-C classes that are registered at application startup, and any that are loaded with NSBundle methods.

        How are you loading and/or registering the Objective-C class you needed to do that for?

        • Just a standard subclass of NSObject, right there in the main bundle.  Not even in a library or anything, it's declared right in the executable! :)

          It did seem like it should've automatically called it, but putting in that method to register the classes manually fixed it, anyway.  I can certainly swap a debug version of CamelBones back in, and try to step through the initialization phase to see what happens...

          • Sherm Pendley
            Sherm Pendley

            This is a hybrid app, right? At what point are you initializing the shared CBPerl instance? Are you doing that in main(), or in a delegate method like applicationDidFinishLaunching?

            I'm asking so I can write a test case that will (hopefully) duplicate the problem.

            • It's an ObjectiveC app, entirely.  It just happens to have the Perl stuff to allow some scripting. :)

              CBPerl, I'm realizing, is initialized when my ScriptingEngine object is initialized; I initialize it in an awakeFromNib (to get the Perl version via the ScriptingEngine object for an about window), rather than in the applicationDidFinishLaunching. 

              That said, I actually also create an instance of the class in question in the same ScriptingEngine initialization; it's definitely already resolved and available.

              • Sherm Pendley
                Sherm Pendley

                Am I following you correctly - does the class you're referring to have some methods in Perl and some in Objective-C? If so, try adding a "void* _sv" instance variable. That's where objects with a Perl component keep a reference to it.

                • Nope.  Let me try to explain it better...

                  I have a class written entirely in ObjectiveC, called ScriptBridge.  This class provides several entry points to drive the application (basically, specific scripting tools).  I then have a Perl module, written entirely in Perl, which calls into this class (handling all the ObjectiveC/Perl name goo, so that Perl module scripts for this application don't ever need to see CamelBones themselves).

                  ScriptBridge is defined in the main application executable, and so should be registered and available at runtime.  The Perl class is in a .pm file embedded in a 'Scripts' directory within the bundle, which I load into CamelBones with a useModule: when I start up.

                  CamelBones crashes if I do a setValue:forKey: to export the ScriptBridge instance to Perl, unless I've manually generated the wrapper beforehand with a call to CBWrapObjectiveCClass().  If I manually generate the wrapper with that call, it all works flawlessly.

                  Hopefully that helps clarify! :)

    • Sherm Pendley
      Sherm Pendley

      BTW, did you know you can use a block eval to catch exceptions? If an exception is thrown, $! is set to an instance of NSException.

      Similarly, calling die() from Perl results in an exception that you can catch with NS_DURING/NS_HANDLER. I haven't tried the newer @try/@catch syntax, but I think it compiles down to the same mechanism, so it should work too.

      • Oh, that's good to know!  I'll definitely modify the code so that Perl die (or inability to load a module someone's mangled) doesn't kill the whole app. ;)