[ Silence ]
Mark Hahnenberg: Good morning everyone.
And if you're interested in that, there is a session that was done on WWDC a number of years ago about the C API.
So what were some of our goals when developing this new API?
Well for one, we want it to be automatic.
The second thing is we want the API to be safe.
So you can pass various objects around and we want it we want you to be able to not we want you to not crash your application if you end up doing something a little squirrely, so we want you to it to be recoverable.
So we don't want there to be, you know, these crazy names that lead with underscores or maybe dollar signs and they're somewhere.
So what are what exactly will you learn today?
Then we'll talk a little bit about memory management.
So, getting these to play nicely together requires some extra attention.
Then we'll talk about threading and how that interacts with the API.
And then we'll speak to a little bit about interfacing with the C API that already exists today.
So I have a simple Cocoa app here.
It has NSTextView.
You can see there are some words in there.
And what you're seeing is that the words that correspond to colors are being highlighted with their corresponding color.
So for example, brown is highlighted brown, red is highlighted red.
And if I don't want to wait around for the random shuffle to get back to the original assignment, I can reset back to the original assignment.
So I can as I type, it will continue to highlight words so you can type red, orange, yellow, but there's a couple bugs.
So for example, we have gray but we don't have G-R-A-Y, that doesn't work correctly.
And also typing capital colors doesn't highlight as we would expect.
And my favorite color cyan is also not highlighted correctly.
So we can fix that pretty easily actually.
I have the script that implements this color mapping.
And what I'm going to do is I'm going to edit the script to give us a new gray or cyan here.
And down here, here's our callback for determining what color a word should be if any.
So, you can see that if I uncomment this, then we will take into account words that have uppercase in them that are still colors.
So I'm going to save this file, go back to my application and I have this Reload button down in the bottom right and then we'll reload the script and now we correctly highlight the colors, and I didn't have to recompile which is kind of neat.
So let's look at how we might implement something like this.
So, here is a simple Hello World program, Hello World.
We use that context and call evaluateScript, evaluating 2 + 2 and that will return a result in a with a type of JSValue and finally, we convert that JSValue to an integer that we can print out to the screen.
So let's talk about these two core data types, JSContext and JSValue.
It corresponds to a single global object, so in web parlance for you guys coming from the web world, it corresponds to a window object.
There is no thing called a window but there is a single global object for global variables.
And the other type is JSValue.
JSValues live inside of a JSContext.
And they have a strong reference to that value.
So keep it alive as long as you're interacting with that JSValue.
And they're tied to a particular JSContext, each JSValue is tied to a particular JSContext.
And why is that?
Well, any JSValue might want to evaluate code which we need a JSContext to do.
And that is also a strong reference, so JSValue keeps alive all of those things that it needs to do its job.
So there's a variety of ways to create JSValues.
This is the you can create things using the corresponding Objective-C primitives like Boolean's, doubles, et cetera.
And you can also create new JSValues and pass an arbitrary Objective-C object.
So, in this particular method, this class method deserves its own slide because a lot of magic happens here.
And we'll talk more about exactly how that works in a second.
Once you have a JSValue, if you get it back from a call or something, you want to be able to access the data that's inside of it so we have various things like converting to a Boolean, to numbers, to dates, strings, et cetera.
You also notice at the bottom, the two object method.
And this allows you to get if you bridge an Objective-C object to a JSValue, this allows you to get that Objective-C object back out of the JSValue.
So first, we load the script from wherever it resides on disk perhaps.
We evaluate the script using the context like we saw earlier.
And since the script defines a single global function, we can use this new subscript notation and pass the name of the function from the context to load that JSValue from the global object, from the global scope.
Once we have that function, we can we simply use callWithArguments and pass this and pass an NSArray of arguments.
So this is this new Objective-C notation for creating array literals.
And finally, we get the result back and we print it.
It should be 120, right?
The factorial function is correct.
Here are the callbacks for the Shuffle and Reset button.
So we load the shuffleFunction from the plug in, and then we call the function with an empty set of arguments.
If you look up here, when we're loading the plug-in, we get the path from the bundle, we load the script from the file and then we use evaluateScript to get the result of loading that plug-in and we store it.
The first is to use blocks, Objective-C blocks.
It's a very powerful technique for maintaining that fidelity that I spoke about earlier.
So let's look how these work exactly.
First is blocks.
So what does that look like?
We can insert a block into the context using this subscript notation that I talked about earlier.
And you'll notice that the block takes an NSDictionary of RGB values as its argument.
And it returns a new NSColor using those red, green and blue values.
And the cool thing about this is that, you notice before that the block accepts an NSDictionary as its argument.
We call this MakeNSColor, and what happens?
Colorforword calls a function and it forwards that call to the Objective-C block.
So although blocks are very easy to use, there are a couple of caveats you have to be careful about when using them.
So, the first is you should avoid capturing JSValues inside of your blocks.
And so if they're captured by the block, you'll leak that memory because you won't be able to release that JSValue.
You should instead you should prefer to pass JSValues as arguments to your blocks.
The second caveat is along similar lines.
You should avoid capturing JSContext inside of your blocks.
And it's for the same reason, the JSContext maintains a strong reference to the global object and it will leak all of your memory when it's captured.
Instead, you should use the class method on JSContext called currentContext inside of the block, and that will return to you the context of the color whoever invoked that block.
This is an example of what not to do.
You create a context, you pass a block, and you use, you capture that context inside of the block, this is bad.
The right way to do it is to create the context, insert the block and then use JSContext currentContext where you were capturing it before.
So now, we talked about blocks, let's talk about JSExport and how that works.
So, let's take a look at what it would look like.
So imagine that I have a MyPoint class represents a two dimensional point, it has an X and a Y property, description, instance method, and a factory method to create new MyPoints, so a class method.
So, you could get their value, you could set their value.
We want the instance methods to look like functions on those objects, so dot description in this case.
And we want class methods to look like functions on these global class objects, in this case, capital MyPoint.
So, the way to get this to work with JSExport is simply to change its interface into a protocol that inherits from JSExport.
So now, we have a MyPoint exports.
So, you'll also notice that when you had your interface for MyPoint now, you don't have to re-list all of those methods because it's a protocol so that's how protocols work.
And that's nice because you don't get a lot of duplication of information.
So if you only want to it's a purely opt-in protocol.
And then your implementation of MyPoint will look just exactly like Objective-C code.
This speaks to that kind of fidelity that we're talking about earlier.
So let's look at how we would use this.
So we allocate our context like before.
We evaluate some geometry script which I'll show you in a second.
Then we create two of our points just like we normally would, alloc init with XY, and we load the function from the context like we saw earlier, in this case, it's euclideanDistance between two points.
Then we can load, for example, a function name midpoint which might want to create a new point given two other points and we can call it the same way that we did before.
We get a result back in the form of a JSValue and we used two object to get the new point back out.
So this is the geometry script that I referenced earlier.
It has two functions, euclideanDistance and midpoint.
They accept two arguments each, point one and point two.
And I'd like to call your attention to how this script uses those properties that were defined on point.
It's completely transparent that these are actually Objective-C objects under the hood.
[ Pause ]
First of all, memory management.
So as you all are probably aware, Objective-C uses ARC, yes.
So what does this mean?
It doesn't matter if you create reference cycles because the garbage collector can handle reference cycles.
You can't just store a JSValue inside of your object, you will very easily create a reference cycle and we'll talk about how to deal with that in a second.
So, here's an example of how you can create a routine cycle doing the wrong thing.
So the ClickHandler makes a reference to the button and it also sets the buttons onClickHandler to itself and then it stores the callback for use later, pretty, pretty pedestrian.
However, you get into a little bit of trouble if you try to implement the setonClickHandler setter like this.
The onClickHandler, if you just assign the JSValue directly into the instance variable of MyButton, then you'll create a routine cycle as you can see here.
So MyButton has a strong reference to its onClickHandler through its JSValue to the ClickHandler object.
And the ClickHandler has a strong reference back to the button through this.button.
And it wouldn't really work to make this a weak reference either because then ClickHandler would disappear and we wouldn't get our callbacks as we expected.
So we need a different type of edge, a different type of reference.
And the name of that reference is JSManagedValue.
So, this is the correct set onClickHandler.
We take the JSValue that's passed to us and we create what's called a JSManagedValue using managedValueWithValue passing the handler there, and we assign that to our onClickHandler field.
Now, what exactly is this addManagedReferenceDeal?
So you can think of addManagedReference as creating a garbage collected reference, it's not a strong reference, it's not a weak reference, it's a new type of reference, it's a garbage collected reference as represented here by the dashed line.
So we resolved our reference cycle here.
So this is how you create weak references.
Otherwise, the reference is released.
So now that we talked about memory management, let's talk a little bit about threading.
But first to talk about threading, we have to talk about virtual machines.
In this case, JSVirtualMachine which we used in the previous slide when we were calling addManagedReference.
So, a JSVirtualMachine is a container that can contain multiple JSContexts and you can have multiple JSVirtualMachines in a single process that have different context and some JSValues live inside of these contexts, and you can pass JSValues between JSContext in the same virtual machine.
But, you can't pass them between JSVirtualMachines.
And the reasons for this are a little bit technical, but shortly, each JSVirtualMachine has its own heap and its own garbage collector.
So if you pass if you were to pass a JSValue from one JSVirtualMachine to another, that particular garbage collector doesn't know how to deal with things from a different heap.
So that's the reason that you're not allowed to do that.
So how does JSVirtualMachine affect threading?
You can call into various JSContext and evaluate code and create values and that sort of thing on different threads and everything will work fine.
However, the locking granularity is at the level of a JSVirtualMachine.
The C API has its inherent warts, but it's very easy to start to convert over to the new Objective-C API.
There's a one to one correspondence between JSValues and JSValueRefs and JSContext and JSGlobalContextRefs.
And we make it very easy to get one where you wanted the other or get the other where you have one.
So, for example, if you have a JSGlobalContextRef, you can call contextWithJSGlobalContextRef and pass that JSGlobalContextRef and we'll give you the appropriate the corresponding JSContext.
The same goes for the other way.
You can call JSGlobalContextRef on the context that you have and we'll give you the C API equivalent.
Same for JSValue.
Now that we looked at all of these advanced features of the API such as memory management, let's take a look at sort of the tip of the iceberg of what is possible using the new Objective-C API in an application.
So I'm going to show you an application called ColorMyCode.
And to give you an idea of what this application is before I start opening things, it's a simple text editor similar along the same lines as ColorMyWords, but it's kind of turned up to 11.
So it's a text editor that can highlight code as many of you probably use something like that.
So, I'm going to open the project here.
Build it. We open a new window.
[ Pause ]
OK and let's save it.
So, we can also this particular I implemented two languages.
OK, I want to do some Scheme.
Let's just save that for now.
Probably you don't want to watch me code Scheme.
So, I'm going to save it as a Scheme file.
And now, the editor is configured to use a different color scheme for Scheme.
And you can see that it highlights different keywords.
So, if I were to type function in here, it doesn't really work because that's not a keyword.
It does things like comments so I can type a comment, "Hello, this is my comment."
It does strings, so string.
Sure, strong, why not.
We have comments, we have block comments, we have strings again, and numbers as well.
So that is that, and if you look at the code here, I'll just show you very briefly, don't be afraid.
Split up into separate plug-ins on this for different ones for highlighting.
In this particular case, we pass a token and based on the type, if it's a keyword, we do one color; if it's an identifier we do another color.
And I don't want to scare you away with kind of the relative complexity of that demo and it only took about a weekend to throw that together and it's actually not very much coded at all.
So, it's definitely possible and it's very, very easy.
So, now that you've seen that, now we talked about native applications outside of web content.
So first of all, why would you want to use this?
Well, for example, you could implement your own custom console for your application that displays web pages.
And you could log in a very specific way like you could log back to the web server or, you know, a variety of things.
You can pass your own objects that you defined, your own native objects and use them inside of your web content.
So, the way to do this is to use the WebFrameLoadDelegate, and this is a delegate that you set on the WebKit WebView.
And you can build your whole native API using that context like I showed you earlier with the subscript notation, you can insert things into the global object and all of that good stuff.
You can evaluate new scripts, et cetera.
And if you viewed some of the old callbacks before like the WebScriptObject interface in the WebFrameLoadDelegate, it replaces those old callbacks gracefully, meaning that if it's running on if your application is running on a client that doesn't have the new API available to it, it will fallback gracefully to use your old implementation of your callbacks.
And a good example of this is the iTunes store on Mac uses a WebView for its content.
So, they just call into that code that they've already written and they can take advantage of that directly in their web content.
So here's a simple example using the console example that I described earlier.
So I defined my MyFrameLoadDelegete and I override the callback.
You can see the second argument is the context, that's the one that I really care about.
And I create a new console using alloc init.
Imagine it's like a kind of a normal console that has like a log that you can call.
And I insert it directly into the global object using the context.
And so here's the HTML that could take advantage of this.
So you'll see I have a normal HTML web page.
In the body there's a button and when you click the button, it calls this handler guy which will then call the myConsole.log function instance method on that Objective-C object that you inserted.
We talked about how to get reference counting and garbage collection to play nicely together using JSManagedValue and addManagedReference.
We talked about threading and how to use threads effectively at the granular area of JSVirtualMachine.
And we talked about using custom objects in WebKit WebViews and using that WebFrameLoadDelegate callback to insert your own native objects into your web context.
So I have a Call to Action.
For all of you who views the C API, I would challenge you to convert one bit of your one small segment of your old code to use the new Objective-C API.
You'll see that it's much more concise where something might have taken five lines before, it might take only one now.
And you'll see that it's really, really easy to do what you were trying to do and it's very concise.
For more information, I contact John Geleynse.
He's the technology evangelist.
The documentation is not current but it's coming.
And of course you can go the Apple Developer Forums.
So related sessions, this is for the people online.
So if you want to know more about web technologies, I'd recommend you to check out these sessions.
Most of them have already passed.
But, yeah, thank you very much.
[ Applause ]