Using KVC for NSObject properties

Discuss the JavaScriptCore Objective-C wrapper/bridge
Post Reply
ddribin
Posts: 19
Joined: Mon May 12, 2008 9:21 am

Using KVC for NSObject properties

Post by ddribin » Wed May 14, 2008 1:20 am

Here's a patch that updates the NSObject and NSDictionary wrappers to use KVC to resolve properties. It also fixes NSNumber conversion when it holds a boolean:

http://www.dribin.org/dave/tmp/wrapper- ... 1.patch.gz

This allows you to pass Objective-C objects to JavaScript and use JavaScript properties to access the values. For example, say you have this class:

Code: Select all

@interface Person : NSObject
{
    NSString * firstName;
    NSString * lastName;
}

@property(copy) NSString * firstName;
@property(copy) NSString * lastName;

@end
If you pass in an instance of Person as a global "person", you could use it like this in JavaScript:

Code: Select all

log(person.firstName);
Because JavaScript properties use valueForKeyPath: under the hood, you can even do crazy stuff like:

Code: Select all

log(array[1]['subarray.@count']);
-Dave

gandreas
Immortal
Posts: 1464
Joined: Wed Feb 04, 2004 6:02 pm
Contact:

Post by gandreas » Thu May 15, 2008 7:48 am

I've grabbed it and definitely like it.

I'm not too sure about the NSNumber boolean conversion, since it relies on internal implementation details that aren't documented. Speaking hypothetically, I'd like to be able to use JSKit on the iPhone, and relying on implementation details of one implementation may not translate well to other implementations.

At the very least, there is still a problem with code that uses kCFBooleanTrue/kCFBooleanFalse (which can happen especially with code that comes from various bridged core routines).

I'll merge this in and try to push out an update - I've also got some fixes for exception handling (and better support for getting exception information), and I've got the start of a "convert .bridgeSupport files" script to make a Quartz bridge. Unfortunately, adding this Quartz bridge would result in requiring compiling under 10.5 (the bridge support files don't indicate what OS symbols come from, so I can't do conditional compilation blocks).

ddribin
Posts: 19
Joined: Mon May 12, 2008 9:21 am

Post by ddribin » Thu May 15, 2008 8:18 am

gandreas wrote:I'm not too sure about the NSNumber boolean conversion, since it relies on internal implementation details that aren't documented. Speaking hypothetically, I'd like to be able to use JSKit on the iPhone, and relying on implementation details of one implementation may not translate well to other implementations.
Yeah, I agree, it's a hack, but kind of necessary. There's no public API to determine if an NSNumber was created with numberWithBool:. With out it, an NSNumber that holds an integer 1 shows up as a boolean on the JavaScript side. I noticed this when trying to print out the length of an NSArray on the JS side:

Code: Select all

log("Count " + people['@count']);
The output is: "Count true" when it should be "Count 1".

If other platforms don't support it, and we can't think of cleaner way to do it, then we should probably just conditionally compile it in on OS X.
At the very least, there is still a problem with code that uses kCFBooleanTrue/kCFBooleanFalse (which can happen especially with code that comes from various bridged core routines).
I don't believe NSNumbers are fully bridged with CFNumbers, so an NSNumber can't really be as CFBoolean, under the hood.

-Dave

gandreas
Immortal
Posts: 1464
Joined: Wed Feb 04, 2004 6:02 pm
Contact:

Post by gandreas » Thu May 15, 2008 2:32 pm

ddribin wrote:
gandreas wrote:I'm not too sure about the NSNumber boolean conversion, since it relies on internal implementation details that aren't documented. Speaking hypothetically, I'd like to be able to use JSKit on the iPhone, and relying on implementation details of one implementation may not translate well to other implementations.
Yeah, I agree, it's a hack, but kind of necessary. There's no public API to determine if an NSNumber was created with numberWithBool:. With out it, an NSNumber that holds an integer 1 shows up as a boolean on the JavaScript side. I noticed this when trying to print out the length of an NSArray on the JS side:

Code: Select all

log("Count " + people['@count']);
The output is: "Count true" when it should be "Count 1".
Yeah, it's pretty ugly - I've seen it a couple of times as well.

The flip problem is that any JavaScript code that does "value === true" still needs to work properly as well.
At the very least, there is still a problem with code that uses kCFBooleanTrue/kCFBooleanFalse (which can happen especially with code that comes from various bridged core routines).
I don't believe NSNumbers are fully bridged with CFNumbers, so an NSNumber can't really be as CFBoolean, under the hood.

-Dave
Actually, while CFNumber is (completely) toll free bridged with NSNumber, CFBoolean is only "partially" bridged - see <http://lists.apple.com/archives/cocoa-d ... 02192.html> for more details.

I should probably examine how PyObjC manages it, and try to adopt a similar solution...

ddribin
Posts: 19
Joined: Mon May 12, 2008 9:21 am

Post by ddribin » Mon May 19, 2008 12:16 am

gandreas wrote:The flip problem is that any JavaScript code that does "value === true" still needs to work properly as well.
I believe this works as expected, so long as "value" is an NSNumber that was created with numberWithBool:YES. At least it seems to work in my quick testing. BOOLs wrapped as NSNumbers are properly returned as JS booleans.
Actually, while CFNumber is (completely) toll free bridged with NSNumber, CFBoolean is only "partially" bridged - see <http> for more details.

I should probably examine how PyObjC manages it, and try to adopt a similar solution...
Probably a good idea.

-Dave

ddribin
Posts: 19
Joined: Mon May 12, 2008 9:21 am

Post by ddribin » Fri May 23, 2008 1:06 am

Here's an updated version of this patch:

http://www.dribin.org/dave/tmp/wrapper- ... 1.patch.gz

Apply to a clean JSKit 0.1b1. It includes faster NSNumber conversion (by avoiding -className) and provides KVC on arrays. The previous patch KVC worked on everything *but* arrays. Arrays would only respond to integer indexes and 'length'. Now you truly can do things like 'array[@count]' or 'array[@lastObject]'.

-Dave

Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests