Temporarily storing Javascript object in Objective-C

90 views
Skip to first unread message

Ian Beck

unread,
Jan 13, 2011, 3:19:55 PM1/13/11
to JSCocoa
Hey there,

I know this is possible, but I'm having trouble figuring out
specifically what I need to do to make it happen. I have a Javascript
object:

var myObject = {
"something": "stuff",
"awesomeness": function() { /* do something */ }
}

And I need to store it temporarily in Objective-C by doing something
like this in Javascript:

myObjCObject.setJSObject(myObject);
// ... time passes ...
var thatObject = myObjCObject.jsObject;
thatObject.awesomeness(); // etc.

The trouble is that I am not sure what type of object/reference I'm
getting in Objective-C, or how best to preserve and then return it. So
far my attempts using JSValueRef and JSValueProtect have lead to non-
descriptive crashes or the object getting lost between storage and
retrieval. Unfortunately, Google has not been helpful in alleviating
my ignorance, so any advice is appreciated.

Ian

Patrick Geiller

unread,
Jan 13, 2011, 8:15:47 PM1/13/11
to jsc...@googlegroups.com

You must use JSValueRefAndContextRef to pass a Javascript object to ObjC, then call JSValueProtect with the global context.


// valueAndContext gives the js object and its associated context (the current call stack).
// This context might be soon destroyed, therefore we must use the main context to protect the value
- (id)setJSObject:(JSValueRefAndContextRef)valueAndContext {
// Get the main context
JSContextRef mainContext = [[JSCocoa controllerFromContext:valueAndContext.ctx] ctx];

// Protect the object
JSValueProtect(mainContext, valueAndContext.value);
}

// Use JSValueRefAndContextRef also when returning your object to js
- (JSValueRefAndContextRef)jsObject
{
JSValueRefAndContextRef returnValue = { NULL, NULL };
returnValue.value = /* your previously stored object */
return returnValue;
}

> --
> JSCocoa: http://inexdo.com/JSCocoa
> Source: http://github.com/parmanoir/jscocoa/tree/master
> Docs: http://code.google.com/p/jscocoa/
> Group: http://groups.google.com/group/jscocoa
> Unsubscribe: jscocoa+u...@googlegroups.com

Ian Beck

unread,
Jan 17, 2011, 7:17:44 PM1/17/11
to JSCocoa
Thanks Patrick! I forgot to try JSValueRefAndContextRef. This is the
Objective-C I am trying based on your code:

- (void)setJSObject:(JSValueRefAndContextRef)jsObject {
// Get the main context
JSContextRef mainContext = [[JSCocoa
controllerFromContext:jsObject.ctx] ctx];
// In .h file defined as: JSValueRef _jsObject;
_jsObject = jsObject.value;
JSValueProtect(mainContext, _jsObject);
}

- (JSValueRefAndContextRef)jsObject {
JSValueRefAndContextRef returnValue = {NULL, NULL};
returnValue.value = _jsObject;
return returnValue;
}

However, this does not work. I am not getting any errors when calling
myObject.setJSObject({"foo": "bar}) in Javascript, but then this:

var storedObject = myObject.jsObject;
log(storedObject.foo);

Results in an error ('Result of expression "storedObject" [undefined]
is not an object') and a segmentation fault that crashes the program.

Is there any obvious reason why this would happen (some oversight on
my part, for instance), or should I make a testing project and try to
debug from there?

Ian

Patrick Geiller

unread,
Jan 21, 2011, 1:25:16 PM1/21/11
to jsc...@googlegroups.com

I don't know :(

I've had JSValueProtect fail while protecting values from webViews and ended up using a global array that stored the values. Where JSValueProtect fails, the array is a root variable of the context and JavascriptCore does keep it around. Look for __gcprotect in JSCocoaPrivateObject.

Ian Beck

unread,
Jan 21, 2011, 2:09:21 PM1/21/11
to jsc...@googlegroups.com
Damn. Okay, I'll try the global array, or else find a workaround that
doesn't require storing the object in Objective-C.

Ian

Reply all
Reply to author
Forward
0 new messages