11
2- // Recursively create a struct
3- function makeStruct ( def ) {
4- if ( typeof def !== 'object' || Object . keys ( def ) . length == 0 ) {
5- return def ;
6- }
7- const name = Object . keys ( def ) [ 0 ] ;
8- const values = def [ name ] ;
9-
10- const structure = MOStruct . structureWithName_memberNames_runtime ( name , Object . keys ( values ) , Mocha . sharedRuntime ( ) ) ;
11-
12- Object . keys ( values ) . map ( member => {
13- structure [ member ] = makeStruct ( values [ member ] ) ;
14- } ) ;
15-
16- return structure ;
17- }
18-
19- const objc_super_typeEncoding = '{objc_super="receiver"@"super_class"#}' ;
20- function make_objc_super ( self , cls ) {
21- return makeStruct ( {
22- objc_super :{
23- receiver :self ,
24- super_class : cls ,
25- } ,
26- } ) ;
27- }
2+ import { object_getInstanceVariable , object_setInstanceVariable , CFunc , SuperCall } from './runtime.js' ;
283
29- // Copy-paste this into 💎Sketch.app and run it 🔥
30- // Scroll to bottom for usage
31-
32- // Due to particularities of the JS bridge, we can't call into MOBridgeSupport objects directly
33- // But, we can ask key value coding to do the dirty work for us ;)
34- function setKeys ( o , d ) {
35- const funcDict = NSMutableDictionary . dictionary ( )
36- funcDict . o = o
37- Object . keys ( d ) . map ( k => funcDict . setValue_forKeyPath ( d [ k ] , "o." + k ) )
38- }
39-
40- // Use any C function, not just ones with BridgeSupport
41- function CFunc ( name , args , retVal ) {
42- function makeArgument ( a ) {
43- if ( ! a ) return null ;
44- const arg = MOBridgeSupportArgument . alloc ( ) . init ( ) ;
45- setKeys ( arg , {
46- type64 : a . type ,
47- } ) ;
48- return arg ;
49- }
50- const func = MOBridgeSupportFunction . alloc ( ) . init ( ) ;
51- setKeys ( func , {
52- name : name ,
53- arguments : args . map ( makeArgument ) ,
54- returnValue : makeArgument ( retVal ) ,
55- } )
56- return func ;
57- }
58-
59- /*
60- @encode (char*) = "*"
61- @encode (id) = "@"
62- @encode (Class) = "#"
63- @encode (void*) = "^v"
64- @encode (CGRect) = "{CGRect={CGPoint=dd}{CGSize=dd}}"
65- @encode (SEL) = ":"
66- */
67-
68- function addStructToBridgeSupport ( key , structDef ) {
69- const def = MOBridgeSupportStruct . alloc ( ) . init ( ) ;
70- setKeys ( def , {
71- name : key ,
72- type : structDef . type ,
73- } ) ;
74- log ( "adding def: " + def ) ;
75-
76- const symbols = MOBridgeSupportController . sharedController ( ) . valueForKey ( 'symbols' ) ;
77- if ( ! symbols ) throw Error ( "Something has changed within bridge support so we can't add our definitions" ) ;
78- symbols [ NSString . stringWithString ( key ) ] = def ;
79- } ;
80-
81- // This assumes the ivar is an object type. Return value is pretty useless.
82- const object_getInstanceVariable = CFunc ( "object_getInstanceVariable" , [ { type : "@" } , { type :'*' } , { type : "^@" } ] , { type : "^{objc_ivar=}" } ) ;
83- // Again, ivar is of object type
84- const object_setInstanceVariable = CFunc ( "object_setInstanceVariable" , [ { type : "@" } , { type :'*' } , { type : "@" } ] , { type : "^{objc_ivar=}" } ) ;
4+ export { SuperCall } ;
855
866// super when returnType is id and args are void
877// id objc_msgSendSuper(struct objc_super *super, SEL op, void)
88- export const SuperInit = SuperCall ( NSStringFromSelector ( "init" ) , [ ] , { type :"@" } ) ;
89- // SuperInit;
90-
91- // You can store this to call your function. this must be bound to the current instance.
92- function SuperCall ( selector , argTypes , returnType ) {
93- const func = CFunc ( "objc_msgSendSuper" , [ { type : '^' + objc_super_typeEncoding } , { type : ":" } , ...argTypes ] , returnType ) ;
94- return function ( ...args ) {
95- const struct = make_objc_super ( this , this . superclass ( ) ) ;
96- const structPtr = MOPointer . alloc ( ) . initWithValue_ ( struct ) ;
97- return func ( structPtr , selector , ...args ) ;
98- } ;
99- }
8+ const SuperInit = SuperCall ( NSStringFromSelector ( "init" ) , [ ] , { type :"@" } ) ;
1009
10110// Returns a real ObjC class. No need to use new.
10211export default function ObjCClass ( defn ) {
@@ -117,21 +26,19 @@ export default function ObjCClass(defn) {
11726 }
11827 }
11928
120- cls . addInstanceMethodWithSelector_function_ ( NSSelectorFromString ( 'init' ) , function ( ) {
121- //const superr = make_objc_super(this, this.superclass());
122- //const superPtr = MOPointer.alloc().initWithValue_(superr);
123- const self = SuperInit . call ( this ) ;
124- ivars . map ( name => {
125- Object . defineProperty ( self , name , {
126- get ( ) { return getIvar ( self , name ) } ,
127- set ( v ) { object_setInstanceVariable ( self , name , v ) } ,
128- } ) ;
129- self [ name ] = defn [ name ] ;
29+ cls . addInstanceMethodWithSelector_function_ ( NSSelectorFromString ( 'init' ) , function ( ) {
30+ const self = SuperInit . call ( this ) ;
31+ ivars . map ( name => {
32+ Object . defineProperty ( self , name , {
33+ get ( ) { return getIvar ( self , name ) } ,
34+ set ( v ) { object_setInstanceVariable ( self , name , v ) } ,
13035 } ) ;
131- // If there is a passsed-in init funciton, call it now.
132- if ( typeof defn . init == 'function' ) defn . init . call ( this ) ;
133- return self ;
36+ self [ name ] = defn [ name ] ;
13437 } ) ;
38+ // If there is a passsed-in init funciton, call it now.
39+ if ( typeof defn . init == 'function' ) defn . init . call ( this ) ;
40+ return self ;
41+ } ) ;
13542
13643 return cls . registerClass ( ) ;
13744} ;
@@ -142,11 +49,3 @@ function getIvar(obj, name) {
14249 return retPtr . value ( ) . retain ( ) . autorelease ( ) ;
14350}
14451
145-
146- /**************************************
147- ************** Usage ******************
148- ***************************************/
149-
150- // We need Mocha to understand what an objc_super is so we can use it as a function argument
151- addStructToBridgeSupport ( 'objc_super' , { type :objc_super_typeEncoding } ) ;
152-
0 commit comments