Skip to content

Commit 006abf0

Browse files
committed
Cleanup, move runtime functions to runtime.js
1 parent 291e1ea commit 006abf0

File tree

2 files changed

+111
-115
lines changed

2 files changed

+111
-115
lines changed

src/index.js

Lines changed: 14 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,11 @@
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.
10211
export 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-

src/runtime.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// You can store this to call your function. this must be bound to the current instance.
2+
export function SuperCall(selector, argTypes, returnType) {
3+
const func = CFunc("objc_msgSendSuper", [{type: '^' + objc_super_typeEncoding}, {type: ":"}, ...argTypes], returnType);
4+
return function(...args) {
5+
const struct = make_objc_super(this, this.superclass());
6+
const structPtr = MOPointer.alloc().initWithValue_(struct);
7+
return func(structPtr, selector, ...args);
8+
};
9+
}
10+
11+
// Recursively create a MOStruct
12+
function makeStruct(def) {
13+
if (typeof def !== 'object' || Object.keys(def).length == 0) {
14+
return def;
15+
}
16+
const name = Object.keys(def)[0];
17+
const values = def[name];
18+
19+
const structure = MOStruct.structureWithName_memberNames_runtime(name, Object.keys(values), Mocha.sharedRuntime());
20+
21+
Object.keys(values).map( member => {
22+
structure[member] = makeStruct(values[member]);
23+
});
24+
25+
return structure;
26+
}
27+
28+
const objc_super_typeEncoding = '{objc_super="receiver"@"super_class"#}';
29+
function make_objc_super(self, cls) {
30+
return makeStruct({
31+
objc_super:{
32+
receiver:self,
33+
super_class: cls,
34+
},
35+
});
36+
}
37+
38+
// Due to particularities of the JS bridge, we can't call into MOBridgeSupport objects directly
39+
// But, we can ask key value coding to do the dirty work for us ;)
40+
function setKeys(o, d) {
41+
const funcDict = NSMutableDictionary.dictionary()
42+
funcDict.o = o
43+
Object.keys(d).map( k => funcDict.setValue_forKeyPath(d[k], "o." + k) )
44+
}
45+
46+
// Use any C function, not just ones with BridgeSupport
47+
export function CFunc(name, args, retVal) {
48+
function makeArgument(a) {
49+
if (!a) return null;
50+
const arg = MOBridgeSupportArgument.alloc().init();
51+
setKeys(arg, {
52+
type64: a.type,
53+
});
54+
return arg;
55+
}
56+
const func = MOBridgeSupportFunction.alloc().init();
57+
setKeys(func, {
58+
name: name,
59+
arguments: args.map(makeArgument),
60+
returnValue: makeArgument(retVal),
61+
})
62+
return func;
63+
}
64+
65+
/*
66+
@encode(char*) = "*"
67+
@encode(id) = "@"
68+
@encode(Class) = "#"
69+
@encode(void*) = "^v"
70+
@encode(CGRect) = "{CGRect={CGPoint=dd}{CGSize=dd}}"
71+
@encode(SEL) = ":"
72+
*/
73+
74+
function addStructToBridgeSupport(key, structDef) {
75+
// OK, so this is probably the nastiest hack in this file.
76+
// We go modify MOBridgeSupportController behind its back and use kvc to add our own definition
77+
// There isn't another API for this though. So the only other way would be to make a real bridgesupport file.
78+
const def = MOBridgeSupportStruct.alloc().init();
79+
setKeys(def, {
80+
name: key,
81+
type: structDef.type,
82+
});
83+
log("adding def: " + def);
84+
85+
const symbols = MOBridgeSupportController.sharedController().valueForKey('symbols');
86+
if (!symbols) throw Error("Something has changed within bridge support so we can't add our definitions");
87+
symbols[NSString.stringWithString(key)] = def;
88+
};
89+
90+
// This assumes the ivar is an object type. Return value is pretty useless.
91+
export const object_getInstanceVariable = CFunc("object_getInstanceVariable", [{type: "@"}, {type:'*'}, {type: "^@"}], {type: "^{objc_ivar=}"});
92+
// Again, ivar is of object type
93+
export const object_setInstanceVariable = CFunc("object_setInstanceVariable", [{type: "@"}, {type:'*'}, {type: "@"}], {type: "^{objc_ivar=}"});
94+
95+
// We need Mocha to understand what an objc_super is so we can use it as a function argument
96+
addStructToBridgeSupport('objc_super', {type:objc_super_typeEncoding});
97+

0 commit comments

Comments
 (0)