Calling Objective-C Methods
The web scripting capabilities of WebKit permit you to access Objective-C properties and call Objective-C methods from the JavaScript scripting environment.
An important but not necessarily obvious fact about this bridge is that it does not allow any JavaScript script to access Objective-C. You cannot access Objective-C properties and methods from a web browser unless a custom plug-in has been installed. The bridge is intended for people using custom plug-ins and JavaScript environments enclosed within WebKit objects (for example, a WebView).
How to Use Objective-C in JavaScript
The WebScripting informal protocol, defined in WebScriptObject.h
, defines methods that you can implement in your Objective-C classes to expose their interfaces to a scripting environment such as JavaScript. Methods and properties can both be exposed. To make a method valid for export, you must assure that its return type and all its arguments are Objective-C objects or basic data types like int
and float
. Structures and non object pointers will not be passed to JavaScript.
Method argument and return types are converted to appropriate types for the scripting environment. For example:
JavaScript numbers are converted to NSNumber objects or basic data types like
int
andfloat
.JavaScript strings are converted to NSString objects.
Other JavaScript objects are wrapped as WebScriptObject instances.
Instances of all other classes are wrapped before being passed to the script, and unwrapped as they return to Objective-C.
As an exception, JavaScript arrays cannot be cleanly mapped to NSArray
objects because they are a hybrid between a numerically-indexed array and an associative array. To avoid loss of data during the mapping, you must instead use the webScriptValueAtIndex:
and setWebScriptValueAtIndex:value:
methods.
A Sample Objective-C Class
Let’s look at a sample class. In this case, we will create an Objective-C address book class and expose it to JavaScript. Let’s start with the class definition:
@interface BasicAddressBook: NSObject { |
} |
+ (BasicAddressBook *)addressBook; |
- (NSString *)nameAtIndex:(int)index; |
@end |
Now we’ll write the code to publish a BasicAddressBook
instance to JavaScript:
BasicAddressBook *littleBlackBook = [BasicAddressBook addressBook]; |
id win = [webView windowScriptObject]; |
[win setValue:littleBlackBook forKey:@"AddressBook"]; |
Once you expose these methods to JavaScript (described at the end of this section), you should be able to access your basic address book from the JavaScript environment and perform actions on it using standard JavaScript functions.
Now, let’s make an example showing how you can use the BasicAddressBook
class instance in JavaScript. In this case, we’ll print the name of a person at a certain index in our address book:
function printNameAtIndex(index) { |
var myaddressbook = window.AddressBook; |
var name = myaddressbook.nameAtIndex_(index); |
document.write(name); |
} |
You may have noticed one oddity in the previous code example. There is an underscore after the JavaScript call to the Objective-C nameAtIndex
method. In JavaScript, it is called nameAtIndex_
. This is an example of the default method renaming scheme in action.
Unless you implement webScriptNameForSelector
to return a custom name, the default construction scheme is used. It is your responsibility to ensure that the returned name is unique to the script invoking this method. If your implementation of webScriptNameForSelector
returns nil
or you do not implement it, the default name for the selector will be constructed as follows:
Any colon (
:
) in the Objective-C selector is replaced by an underscore (_
).Any underscore in the Objective-C selector is prefixed with a dollar sign (
$
).Any dollar sign in the Objective-C selector is prefixed with another dollar sign.
The following table shows example results of the default method name constructor:
Objective-C selector | Default script name for selector |
---|---|
|
|
|
|
|
|
|
|
Since the default construction for a method name can be confusing depending on its Objective-C name, you would benefit yourself and the users of your class if you implement webScriptNameForSelector
and return more human-readable names for your methods.
Getting back to the BasicAddressBook, now we’ll implement webScriptNameForSelector
and isSelectorExcludedFromWebScript
for our nameAtIndex
method. In our BasicAddressBook class implementation, we’ll add this:
+ (NSString *) webScriptNameForSelector:(SEL)sel |
{ |
... |
if (sel == @selector(nameAtIndex:)) |
name = @"nameAtIndex"; |
return name; |
} |
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector |
{ |
if (sel == @selector(nameAtIndex:)) return NO; |
return YES; |
} |
Now we can change our JavaScript code to reflect our more logical method name:
function printNameAtIndex(index) { |
var myaddressbook = window.AddressBook; |
var name = myaddressbook.nameAtIndex(index); |
document.write(name); |
} |
Other Resources
For more information about using Objective-C from JavaScript and vice versa, see the following documents:
CallJS sample code shows how to call JavaScript from Objective-C and vice versa.
Birthdays sample code shows how to use a WebKit plug-in from JavaScript.
WebKit Objective-C Framework Reference provides more information on excluding methods and properties from the JavaScript environment.
WebKit Plug-In Programming Topics provides general information about writing WebKit plug-ins.
Copyright © 2010 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2010-02-01