Search code examples
objective-cjavascript-automation

Obtaining a list of class names with objc_getClassList in JavaScript for Automation


By using ObjC.bindFunction in JXA, we can obtain an integer result from objc_getClassList.

Does anyone understand the types and bridging issues well enough to find a route to getting a list of class name strings returned by objc_getClassList into the JavaScript for Automation JSContext ?

(The code below returns only an [Object Ref] string)

(() => {
    'use strict';

    ObjC.import('stdlib');


    ObjC.bindFunction('CFMakeCollectable', [ 'id', [ 'void *' ] ]);

    ObjC.bindFunction('objc_getClassList', ['int', ['void *', 'int']]);

    var classes = Ref();

    const intClasses = $.objc_getClassList(null, 0);

    $.objc_getClassList(classes, intClasses);

    $.CFMakeCollectable(classes);

    return [intClasses, classes];

    //-> [11411, [object Ref]]

})();

Solution

  • The objc_getClassList function is expecting us to provide it with a buffer of memory to copy the class list into. Normally, JXA would treat the return type of malloc as a C array of unsigned chars, but using bindFunction we can cast malloc's return type to a C array of pointers, and make objc_getClassList's first argument match that type. Then, it's just a matter of indexing into the buffer (of type Ref) and passing that value into class_getName.

    ObjC.bindFunction('objc_getClassList', ['int', ['void**', 'int']])
    ObjC.bindFunction('malloc', ['void**', ['int']])
    ObjC.bindFunction('class_getName', ['char *', ['void*']])
    
    const numClasses = $.objc_getClassList(undefined, 0)
    const classes = $.malloc(8*numClasses)
    $.objc_getClassList(classes, numClasses)
    for (i=0; i<numClasses; i++) {
      console.log("classes[" + i + "]: " + $.class_getName(classes[i]))
    }