Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot call UIApplicationMain() internalFieldCount() > 0 assert #14

Closed
radare opened this issue May 6, 2012 · 11 comments
Closed

Cannot call UIApplicationMain() internalFieldCount() > 0 assert #14

radare opened this issue May 6, 2012 · 11 comments

Comments

@radare
Copy link

radare commented May 6, 2012

I have compiled the nodobjc nodejs module (node-ffi, libxmljs) for iOS, and I'm using it on a jailbreaked iOS 5.0.1. with node from cydia.

The first function to create an iOS app is UIApplicationMain().

This function is described in the BridgeSupport files that can be found here (https://github.com/innoying/iOS-BridgeSupport) (extract the contents of src/ to /).

This is the code i'm trying to run:

  var $ = require('NodObjC')
  $.import ('UIKit')
  var pool = $.NSAutoreleasePool('alloc')('init')
  console.log ($.UIScreen);
  console.log ($.UIApplicationMain);
  var str = $.NSString('stringWithUTF8String', "hello")
  var str2 = $.NSString('stringWithUTF8String', "world")
  var ret = $.UIApplicationMain (0, [], str, str2);
  console.log (ret);
  pool ('release');

This is the output:

$ node uikit.js 
[Class: UIScreen]
{ [Function: unwrapper]
  retval: { type: 'i' },
  args: [ { type: 'i' }, { type: '^*' }, { type: '@' }, { type: '@' } ],
  pointer: <Pointer address="927458049" allocated="0" free="false">,
  info: 
   { _name: 'function',
     name: 'UIApplicationMain',
     args: [ [Object], [Object], [Object], [Object] ],
     retval: { type: 'i' } } }
Assertion failed: (handle->InternalFieldCount() > 0), function Unwrap, file /var/root/.node-gyp/0.6.14/src/node_object_wrap.h, line 52.
Abort trap: 6

Looks like there's a problem trying to unwrap the function arguments. How is ^* (char**) suposed to be used? is this a bug in nodobjc? am i doing something wrong?

@TooTallNate
Copy link
Owner

Oh I think I see. Yes, it's the char ** arg that's not right. It's expecting a "pointer" type, so try passing ffi.Pointer.NULL there, to pass in the null pointer.

@radare
Copy link
Author

radare commented May 6, 2012

Thanks! this code seems to work:

var ret = $.UIApplicationMain (0, ffi.Pointer.NULL, null, null); 

But I'm unable to pass a NSString on the 3rd/4th arguments. Is this code fine?

var str = $.NSString('stringWithUTF8String', "hello world")
$.UIApplicationMain(0, ffi.Pointer.NULL, str, null);

Output is:

2012-05-07 01:03:13.593 node[65824:707] *** Assertion failure in int UIApplicationMain(int, char **, NSString *, NSString *)(), /SourceCache/UIKit/UIKit-1912.3/UIApplication.m:1568

For this :

var ret = $.UIApplicationMain (0, ffi.Pointer.NULL, "FooClass", null);

i get

Assertion failed: (!handle.IsEmpty()), function Unwrap, file /var/root/.node-gyp/0.6.14/src/node_object_wrap.h, line 51.

How are strings suposed to be passed here?

@TooTallNate
Copy link
Owner

Your first version should work:

var str = $.NSString('stringWithUTF8String', "hello world")
$.UIApplicationMain(0, ffi.Pointer.NULL, str, null);

Note that the assertion error is coming from within UIApplication.m, so I believe it's going through properly, just something else incorrect about the string itself (like the Class not existing maybe).

Try running gdb on node and your script and seeing what happens.

@radare
Copy link
Author

radare commented May 7, 2012

gdb didnt stops on the assert. i tried placing a breakpoing on the symbol, but steping takes forever.. would be better to have a simpler test case for this i think.

btw, ios-bridgesupport bricks springboard.. which is kinda annoying because you are forced to reflash the phone :) I have been investigating the issue, and I will like to know if there's any way to specify a different path to find those bridgesupport files.

Thanks

@bored-engineer
Copy link

I agree. I've had similar issues in the past. The ability to pull bridgesupport files from an external location would be very appreciated.

@radare
Copy link
Author

radare commented May 10, 2012

I have modified the NodObjC library (lib/import.js) to load the bridgesupport from "/usr/local/System/Library/Frameworks".

That worked fine, so i will modify my ios-bridgesupport cydia package to install there. If there's any BS directory in the filesystem, the SpringBoard will crash and you'll get a bricked iDevice.

It would be good to have a standard path for this, or handle an environment variable to choose the user-defined path.

After this I created an standalone /Applications/NodeJS.app with icon, launcher script and nodejs hello world for iOS.
The problem i'm facing now is related to the subclassing.

@TooTallNate i dont need to debug anything. by googling a bit I found that the assert in UIApplicationMain means that the referenced class does not exist. So i registered.

var $ = require('NodObjC')
var ffi = require ('node-ffi')

$.import ('UIKit')
var pool = $.NSAutoreleasePool('alloc')('init')

/* load AppDelegate */
var AppDelegate = $.NSObject.extend ('AppDelegate')
AppDelegate('respondsToSelector','viewDidLoad');
AppDelegate.addMethod('viewDidLoad', 'v@:@',
    function (self, _cmd, notif) {
        console.log('GOT VIEW DID LOAD');
    })
AppDelegate.addMethod('didFinishLaunching', 'v@:@',
    function (self, _cmd, notif) {
        console.log('got applicationDidFinishLauching')
        console.log(notif)
    })
AppDelegate.register()

var str = $.NSString('stringWithUTF8String', "AppDelegate"
var ret = $.UIApplicationMain (0, ffi.Pointer.NULL, null, str);

The problem is that applicationDidFinishLaunching is never called, so I can't initialize the window and the OS kills the app. I need to define the AppDelegate class in code to match:

@interface AppDelegate : NSObject <UIApplicationDelegate> {
   ...

How can I do this? i can't find any way to specify that this object will understand the UIApplicatinDelegate protocol..

@TooTallNate
Copy link
Owner

@radare So I think you're simply not registering the proper methods to invoke. It should be applicationDidFinishLaunching: (also note the : at the end). So change it to that and you should be good.

To answer your second question, you don't actually have to specify anywhere that the object implements the UIApplicationDelegate. This information in Obj-C code is only used by the compiler, so for NodObjC you just need to make sure that the anticipated methods do exist.

@TooTallNate
Copy link
Owner

Also:

AppDelegate('respondsToSelector','viewDidLoad');

^ FYI, that line doesn't seem to do anything. respondsToSelector: returns a bool true or false (false in this case, since "viewDidLoad" isn't registered yet), and you're supposed to use the return value for something.

@TooTallNate
Copy link
Owner

P.S. when you get something that actually boot up, please show me your code! It would be great to add an iOS app to the examples dir of the repo.

I'm gonna close this issue, but open another one about the more flexible BridgeSupport file locations and I'll try to get to that soon.

@radare
Copy link
Author

radare commented May 10, 2012

Sorry for those misstakes. I tried with:

AppDelegate.addMethod('applicationDidFinishLa
unching:', 'v@:@',

And the fuction was never called :/ maybe this is not the place to discuss this :)

I plan to make cydia package for the module and a sample app too.

Thanks!

@TooTallNate
Copy link
Owner

@radare No prob! And if you're looking for more support come to the #NodObjC IRC room on the freenode network.

P.S. if you're looking for some inspiration, check out the OS X GUI app example: https://github.com/TooTallNate/NodObjC/blob/master/examples/NodeCocoaHelloWorld.app/Contents/MacOS/app.js

^ I assume only minor tweaks would be needed to get an iOS app going...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants