I’m trying to hook up a global exception handler using NSSetUncaughtExceptionHandler in a Rubymotion app. And I can’t figure out how to do it, probably I’m using Rubymotion function pointer syntax incorrectly.
In application(application, didFinishLaunchingWithOptions:launchOptions) I have:
NSSetUncaughtExceptionHandler nil do |exception|
NSLog "exception handler block"
applicationFailedWithException(exception)
end
And the handler (which is never called):
def applicationFailedWithException(exception)
NSLog "applicationFailedWithException"
end
Then, in runtime, when some NoMethodError happens somewhere neither the exception handler block, neither the handler method are called. I’ve tried both in the Simulator and on the device — no success.
P.S. Is there a way to get the ruby methods stack in the crash log, the last application method in the crash log is always the rb_rb2oc_exc_handler instead of the app-specific method, and that’s weird.
Thanks
Update 2015
It seems that with the newer versions of the Rubymotion you have to save a references to the handler in an instance variable, otherwise it will not work. So it should look like:
def application(application, didFinishLaunchingWithOptions:launchOptions)
@exceptionHandler = lambda { |exception| uncaughtExceptionHandler(exception) }
# or you can use a method reference, which is the same
# @exceptionHandler = method :uncaughtExceptionHandler
NSSetUncaughtExceptionHandler @exceptionHandler
...
end
def uncaughtExceptionHandler(exception)
# log it or send it to crashlytics / flurry / whatever
NSLog "Fatal exception catched\nName: #{exception.name}\nReason: # {exception.reason}\nInfo#{exception.userInfo}"
end
To get this to work, I had to assign a block to a variable, then use that variable:
If I then punch in something like
NSException.raise("test", format: "test")in the REPL, I’ll see NSLog do it’s thing:Theoretically, you should be able to nest the lambda directly as the parameter rather than assigning it to a variable first, but I don’t think RubyMotion properly retains the block and the application crashes without error if you try it.