Mac OS • 55:13
This session covers advanced Cocoa topics such as services, file wrappers, runloop, drag and drop, and printing. Some of the recent changes in Cocoa are also presented.
Speakers: Heather Hickman, Mark Piccirelli, Doug Davidson, Chuck Pisula
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
just a little bit of what we're going to cover today. We're going to build on the overview and the using Cocoa session that you just saw and just dig a little bit deeper for these issues. Drag and drop, printing, services, things that Ali mentioned before. So I'm not going to waste any more time. Please help me bring to the stage Cocoa Frameworks Engineer, Mark Piccirelli.
The first thing we're going to talk about is drag and drop. It's an important part of so many programs' user interfaces because Cocoa has good, straightforward support for it. We'll talk about how you register drag targets in your application, how you provide drag feedback when the user drags things over your program's windows, how you handle drops when the user actually drops something, how you initiate drag and drop operations in response to user events in one of your programs' use. And for those of you who have been programming after for a while, I'll briefly mention some of the new drag and drop features in Mac OS X.
So before the user can drag anything onto your program, you have to register the program's drop targets. Now you can register windows as drop targets, but more typically you register specific views in the windows of your program. To do this, you call NSView's register for drag types method, passing it an array of pasteboard data type names, indicating exactly what types the user can drop onto your program's views.
For example, if you subclass NSView, you should call register for drag types in the views initializer method. If you do this, it's also a good idea to call unregister drag types in the views dialog method. Now views that you register to be drop targets must implement methods of the NSDraggingDestination protocol.
The first one of these methods you have to worry about is dragging entered. When the user drags something into one of your program's views, Cocoa will send the view a dragging entered message. This is your opportunity to draw visual feedback, something like an insertion pointer if the view is displaying text. And your view should also determine what sort of drag operation this is going to be. Is copying being done? Is moving being done? Or if it's applicable, is nothing being done because it's not allowed right now?
The information that the view needs to determine these kind of things is available in an NSDraggingInfo object, an object that implements the methods of the NSDraggingInfo protocol. Every one of the methods in the NSDraggingDestination protocol is past an instance of one of these objects. So I'll briefly talk about this other protocol before bouncing back to NSDraggingDestination.
So as I mentioned, an NSDRAGON info object is passed to each of your NSDRAGON destination methods. Now remember what I mentioned before about how your drop target has to determine exactly what sort of drop operation this is. Part of the information it needs to figure that out is based on what drag operations the dragging source supports. And your drop target can find that out by consulting the dragging source operation mask method of the NSDRAGON info protocol. It also might need access to the data that's actually being dragged, and it can get access to that using the dragging pasteboard method.
Back to the methods of the NSDragging destination protocol, which again, each one of them is passed in NSDraggingInfoObject. DraggingUpdated, unlike DraggingEntered, which is called just once when the user drags something onto one of your views, is called over and over again as the user drags things around over your view. You should be redrawing the visual feedback you're providing, if any. And if you do this, be efficient, because this method is called over and over again as the mouse moves. So any flickering or delays will be very noticeable.
One thing you don't have to worry about, one nice thing that Cocoa provides for you, is auto-scrolling. If you've worked in other systems, you know it's a lot of work to deal with the issue of the user dragging something off the bottom of the view. You have to move the scroll bars around.
It's a lot of work sometimes. In Cocoa, it's not a lot of work. If your view is a sub-view and a scroll view, NSScrollView will take care of all this for you. And the other method that's involved in providing drag feedback is dragging exited. If the user drags something away from your view, without actually dropping it, your dragging exited method will be invoked. This is your opportunity to clear the visual feedback that you've been drawing.
Now if the user actually does drop something, your drop target will be sent a sequence of methods, prepare for drag operation, perform drag operation, and conclude drag operation. If everything goes well, all three of them will be sent. So you're wondering, why are there three of them? Why isn't it just one method? Well, you really should do all the main stuff and perform drag operation, but it's necessary to split a few things off from the other things.
For example, in the case of a drag and drop operation that implies moving, the source has to do things too. Once the dragging destination has copied the drag data into its stuff, the dragging source has to delete it. And the way we make sure that all this occurs safely is breaking this up like this. So perform drag operation, your dragging destination is called, then the dragging source is told that it can delete any information that was dragged if it needs to. And then your dragging destination's conclude drag operation method is called.
The other half of providing drag and drop support in your Cocoa application is initiating drag and drops in response to user events, when they pick something up in one of your views. Well, historically, the case of the user picking up file icons or something like that has been common enough that we provide a specific method for it that you can see there. For everything else, NSView has a convenience function, drag image at offset event pasteboard source slide back. And I won't get into all those arguments. There's a bunch of them. They're all very well documented, too. But I will, too, bring up two things that are important.
We get a lot of questions about, from developers, who need to take a snapshot of a piece of their view to provide us that image that gets dragged around. I can't give you the entire answer because it's pretty long, but the hardest to guess part of it is to call NSBitmapImageRep in it with focusDirect.
So that's your hint about how to get that. Another thing you can do... Just as there is an NSDraggingDestination protocol, Cocoa has an NSDraggingSource protocol. I won't get into it in too much detail here because it's much less common to have to customize the operation of the dragging source, but it's there.
So, and if you've been working with AppKit for a long time, say pre-Mac OS 10.0, you should be aware that there are two new operations, NSDragOperationMove and NSDragOperationDelete. That list that showed up on a few slides ago included these. You might have been wondering where they came from.
They provide a little bit richer semantics than just plain old NSDragOperationGeneric, which was used before. And also, we now have drag and drop in our text subsystem, so our text subsystem's classes have a few new methods that you can override, and also the text subsystem classes' delegate methods have a few additions, too.
So the next thing I'll go into is NS Table View because it's a good example of one of the sophisticated controls that Cocoa provides. You've seen them all over. They display data in a table and allow the user to edit values if you want to let them do that and resize and rearrange columns.
and real quick, I'll go into what you have to do to provide the data that the table view displays. Some of the things you can do to handle the user events that can occur in a table view. And if you really need to do serious customization, I'll introduce the concept of table view cells.
So, providing table view data, another protocol, another thing that defines a set of methods that you can implement if need be. The one for NS table data source, and NS table data source is what an NS table view consults to get the data it displays, includes two methods that you'll almost certainly have to implement, number of rows in table view, and table view object for table column row.
Now, you can pretty much guess what the first one is supposed to return. The second one can return pretty much any object within the limitations of what the table view can handle. A standard NS table view can handle strings and numbers with no trouble. and if you're letting the user edit the data that shows up in a table view, you can implement table view set object value for table column row, which is pretty easy too.
So handling table view events. Just as table view-- well, NS table view is unique in that it provides-- it depends on these data sources. It is very common among Cocoa classes, however, to depend on delegates. And NS table view defines a set of delegate methods, much like many other Cocoa classes do. I'll single one out because it's a good example of Cocoa providing flexibility without too much complexability. And that's table view will display cell for table column row.
and that is sent to your table views delegate right before each time a table view is about to display a cell. And that's your option, that's your opportunity to do simple things like setting up fonts or colors for drawing and things like that. Affecting the display of the cell without having to do anything too clever or difficult. And then the table view delegate methods include a bunch of other things for controlling selection and editing policies.
Whether or not you're letting the user select many different rows at one time or just one. Whether or not you're letting the user edit things or not. So stuff like that. And there's also methods that provide, one of the ways that your table view delegate can find out about user events that occur in a table view.
The next step of table view customization is to provide your own kind of cells to the table view. So as I mentioned on an earlier slide, by default, NS Table Views can display numbers and strings without any trouble. And that's because they use instances of one of our classes called NS Text Field Cells.
Well, you can provide other cells if you need to. And as you can see on the slide, there's more than one way to do it. You can do it by overriding or by setting things up after the table view has been instantiated. So if you do this, if you're willing to provide your own kind of cells, you can take total control of all the displaying, of custom drawing, highlighting, and you can even have your table view display objects other than numbers and strings, whatever you need.
So one thing you don't need to provide new cells for is simple things like determining policy. If you just want to affect the editability of an NS TableView cells, well, the delegate can do that. You don't have to, you know, provide new cells for that. and no discussion of NS Table View would be complete without mentioning its most well-known subclass, NS Outline View, which displays pretty much the same stuff but can display hierarchical data. I'm sure you've all seen these around in programs like Mail and Project Builder and other places.
and others. So very quickly, NSOutlineView is not surprisingly a subclass of NSTableView. It follows a lot of the same patterns. The biggest difference is that instead of getting its data from an NSTable data source, it depends on an NSOutlineView data source for its data. An NSOutlineView data source, the interface that's declared by it is very similar to NSTable data sources with an important difference because the data can be hierarchically organized. It provides a few other methods for determining whether or not an item has child items and if so, how many there are.
Another important distinction is the fact that NS Table View or NS Table Data Source identifies rows with a simple integer. And why not? That's the simplest way to do it. That's really not an option with outline views because row indices, things like that, are changing while the user is playing with the little disclosure triangles and things like that. So all the items that are displayed in an outline view and passed across the NS Outline View Data Source protocol are identified by object references.
Next topic I want to talk to you about is printing. I want you to know what you get for free in Cocoa. It's a bunch. I also want you to know the limits of what you get for free because some people have trouble finding them. And I also want you to know that when you go past those limits, even very advanced printing in Cocoa is still pretty easy.
So real quick, I'll go through what views do automatically, what sort of printing they support without much effort at all on your part. I'll talk about what you have to do if you want to take control of the page setup that's involved in printing. I'll introduce the concept of print operations and quickly summarize the things we do as far as pagination goes.
Simple printing of views. Views can print themselves without any trouble at all. Your review has a print method. For example, if you have a file menu with a print item in it, and it's hooked up to the print action, and it's sending the print action down the responder chain, the first view on the responder chain will print itself when it sees that. So it'll take care of putting up the print dialog and things like that. For its print setting, it will use a shared NS Print Info. I'll take more on NS Print Info in a second.
Before I go on to more advanced customization, let me just point out really quick, if the only difference in your view, the only customization you're considering is that you might want to do things a little differently on the screen from what you see on the printer, well, there's a very easy way to find out which of you is drawing to the printer or the screen, and that's the current context drawing to screen method.
So page setup. Very simple applications can just depend on what Cocoa already has built into it. But if you're doing a more full-featured application, you're going to have to know a few classes. The first one of which is NS Print Info, which encapsulates all the parameters of a print job.
It includes, among other things, all the things that the user can set up in a print panel, or a print dialog rather, like page size and orientation and scaling. The Cocoa class that actually presents the print dialog or sheet, whichever, is called NS Page Layout. And you can see there are the two methods that you use to do that.
If your application is document based, if you're using NS Document, you don't really have to worry about too much of this. I try and start going to what you don't get for free, but I immediately run into what you do get for free again. NS Document will take care of all this for you. So if it's a document based app, you're nearly off the hook.
Print operations. When you start taking control of printing, you know, not just letting a view print itself, you have to learn this class. NS print operation. An NS print operation is, as the name implies, what actually does printing. So when you create it, you specify an NS print info that contains the parameters of printing and the view that's to be printed, and eventually you'll run it.
Now which view should be printed? Well you have a couple of options. Text edit, for example, and I do mean for example. You have the source code so you can check this out. Print's one of the views that's already on the screen. The one that you see in the window is just the same view that gets printed by the print operation.
Sketch, on the other hand, another sample program, creates a view just for printing and this view only lives for the lifetime of the print job. So there's advantages and disadvantages to both ways. I suggest you check out the source code for those two and there's plenty of pointers in there.
So an NS document. NS document can't do everything for you. So if you're providing printing in a document-based application, it does provide the obvious place for you to do the printing. It's in the print showing print panel method, which you should override. And if you do that, and you create a print operation in there, and you take the NS print info that the NS document was maintaining for you, keeping around, and you set up your view, when you actually run the operation, you should run it using the run modal print operation delegate did run selector context info method. method.
and that will take care of presenting the sheet because of course we always prefer sheets when it's reasonable. It will take care of presenting the sheet on the proper document window. So, and one more thing you should know about printing is pagination. We have very flexible pagination. For simple cases, even for cases that aren't so simple, you can set margins in the NS Print Info and then set a few pagination modes that we support on a horizontal and vertical basis. Fit pagination, for instance, will scale a view to fit within one page. Clip pagination will just clip it right there. And automatic pagination will split up the view into pieces. And put them on a range of pages.
For more complex situations, when you have to take over, you can override the nose page range method of the view that's being printed and return yes. You'll also have to return the range of pages that's being printed. And then you should also override NS view rect for page. And Cocoa's printing system will call that repeatedly, finding out what piece of the view should be drawn for each page. And during the printing process, it will tell the view to draw that piece. on that page.
One last thing I want to mention is file wrappers. NS file wrapper, a class of ours. What is it? It holds the contents and attributes of a file or a directory's worth of files in memory. Why is this worth mentioning? Well, because it's such an easy way to manage file attachments. When you drag a file into text edit or into a mail message, for instance, and the icon appears, that's NS file wrapper managing all that for you, making the icon available, taking care of things like that.
It's also an easy way to read file packages. If you're not familiar with the concept of file packages yet, a file package is a directory on a Mac OS X system that looks just like a document to the user in the finder. So it's a convenient way to get a few things done, and file wrappers support them very nicely. It does this because a file wrapper can actually wrap a directory also.
And when it does that, you end up with a hierarchy of these NS file wrapper objects. And you get to the sub file wrappers using directory entries, or dictionary entries, as is common in Cocoa. And the operations on a file wrapper are recursive, so if you're doing something like copying an NS file wrapper, all the sub file wrappers inside will be copied also.
So what other kind of things can you do with the file wrapper? As you might guess, you might want to get the data that corresponds to the file that's being wrapped. And you do that, and of course it provides a method for that, and it returns one of our NSData objects for that.
You can get and set the file attributes on a file wrapper, and get the icon also for displaying in places like text edit or a mail message, wherever you're doing a file attachment or something like that. One neat feature is that if a file wrapper has been instantiated by just copying the contents of something off of disk into memory, file wrapper will keep track of that.
And if you need to, you can ask the file wrapper to check to see if the copy on disk has changed. And if so, you can ask it to update to that copy on disk also. And the last good thing you can do with file wrappers is you can serialize, you can flatten them for putting places like the pasteboard. At this point, please welcome to the stage Doug Davidson so he can talk about services.
Thanks, Mark. Now, we had a tantalizing glimpse of services in the last session, so I'm here to tell you something more about them. And to do that, I want to start by describing services by comparison with something that's not a service, and that is the bold menu item in an application. Now, when the user picks the bold menu item, you can think of what is happening as, in effect, the current selection is being copied, transformed so it is bold, and then pasted back in place.
Now, that's a very simple operation. It's built into every application. But suppose you have some custom operation that your application knows how to perform, and you think it's so great that you want to provide it not only in your application, but in your application as well. And you want to make sure that you're not only providing it in your application, but you're also providing it in your application as well.
So, you can think of what's happening in your application. Now, when the user picks the bold menu item, you can think of what is happening as, in effect, the current selection is being copied, transforms so it is bold, and then paste it back in place. Now, that's a very simple operation, but in every other application as well.
Now, if you want to do that, you can use a service. And the way it works is that when that service is requested, the current selection is copied, put on a special pasteboard, shipped off to your application. Your application will be launched if it's not already running. And you perform your special operation on it, put the result back on the pasteboard, get shipped back to the originating application, and then that's pasted back in.
Now, not every service has to follow this exact pattern. For example, the magic typer of the last session didn't take any data, it just returned some data on the pasteboard. Or there can be services that just take data and don't return anything. And the thing that the service takes or returns, it doesn't have to be text, it can be any sort of thing that can be copied and pasted.
So what does an application have to do to support use of services? Well, this is Cocoa. The answer is absolutely nothing. The use of services is automatic. Your standard Cocoa menu, main menu, will have a services menu in it. The app kit will automatically populate it with entries for all the services available on the system. The user just picks it and the rest happens automatically.
There are a couple of things you might want to do. It is possible to invoke services programmatically if you want to. Also, if you have a custom view, the things you need to do to support the use of services on it are essentially the same sort of things that you need to do to support copy and paste.
You need to be able to take the current selection, put it on the pasteboard, or take something from the pasteboard and put it in the current selection. Also, if you have a custom pasteboard type, then you have to register that so that the App Kit can know to check for any services that might take or return that type.
So the interesting question is, what does your application have to do in order to provide a service? Now, in order to provide a service, there are three things you have to do. First one is to implement one single method. It looks something like this. And you'll be handed a pasteboard, optionally some extra data.
You take what comes in on the pasteboard, transform it, put it back, and send it back. And if there's an error, you can return an error string. There are some examples. For example, there's a simple service example on your disk. TextEdit also provides a service. Here is just the basic skeleton of what that service-providing method might look like.
take the string off the pasteboard, one line to perform your operation, and then two more lines to say what type you're putting back on the pasteboard and put the value back on the pasteboard. That's all. That's point number one. So the second thing you need to do is that when your application is launched, you need to register the object that implements this method as the service provider for your application. There's one service provider per application. That's point number two.
And point number three is that you need to add an entry to the Info.plist in your application bundle. And what that does is to describe the service or possibly multiple services that your application provides, saying what the name is, what types it will take, what types it will return, menu items, and possibly keyboard equivalents. Thank you.
Okay. Now next, I'd like to discuss a few topics down at the foundation level. First of all, the runloop. Cocoa applications are fundamentally event-driven. That is, events come in, they're handled, and we go back and wait for the next event to come in. Now, the underlying machinery that supports this is the runloop, NSRunloop, the foundation.
And we call it a runloop because we say that it runs and that it loops. But mainly what a runloop does is it waits. It waits for something interesting to happen. Then it tells you about it. You handle it. It goes back and it waits again. And the things it waits for can be any of a wide variety of things.
It might be the arrival of a Mach message. It might be the arrival of a network packet. It might just be the arrival of some specific time. But what the runloop can do is to wait for all of these things to gather efficiently without pulling, without using any processor resources. And that turns out to be a very powerful thing.
and others. Now, there's just one runloop per thread that does all the waiting for that thread. Typically in an AppKit-based application, the AppKit will run the runloop for you in the main thread. You wouldn't have to do that, but under other circumstances, you may wish to run the runloop for your thread by yourself. Now, runloops can have modes.
It may be that you don't want to wait for every possible thing every time you run the runloop. For example, you might not want to have a certain timer fire while you are, let us say, tracking mouse moves. So it is possible to run a runloop in any -- in a number of different modes. And when you add a source to the runloop, you register it for a single mode or a set of modes.
And only those runloops that are registered for the particular mode that is running are actually active. The default runloop that you would use most of the time and that probably will be used most of the time when the runloop is running, the AppKit has a couple of others that you'll see. For example, one that's used when a modal panel is up and another that's used typically when it's tracking mouse moves in a widget. And you could register for all of these together as the common modes.
Now, runloop by itself is not terribly interesting. What's interesting is what you can do with it. That is, the things you can wait for. And one of the things I said you could wait for was the arrival of a certain time. To do that, you use an NS timer.
An NS timer can wait for a single time or a repeating sequence of times. For example, that silly worm in the last session was animated using a timer that waited for a repeating sequence of times. And the way this works is that when this timer is added to a runloop in a particular mode, if the runloop is running in that mode, it checks to see if the time for that timer to fire has arrived.
And if it has, then it tells you. That is, an object of your choice will be sent a method of your choice when that occurs. and of course if you have a one shot timer it's automatically invalidated after it has fired. If you have a repeating timer then you would have to invalidate it yourself when you no longer want it to be used.
Among the other things you could wait for, I said, were Mach messages, network packets, things like that. If you really want to wait for raw Mach messages or raw network packets, you can do that at the core foundation level with some core foundation runloop sources. And I'll probably mention that tomorrow in the core foundation session. At the foundation level, we have a somewhat more abstracted object based on those, and that is NSPort.
And what NSPort allows you to do is to send what's called an NSPort message from one Cocoa process to another. And the contents of a port message is mainly just an NSData, a bag of bytes. It can also optionally include some references to ports that can be sent across. And an NSPort message is sent. are all presented. I'm going to show you a little bit of the process of how to use the Cocoa Topics. It's a fairly simple, easy-to-use, but rather low-level, inter-process communication mechanism.
A more interesting thing about MS Ports is that they're the foundation of what's known as distributed objects. Now what distributed objects allows you to do is to send method calls to objects transparently across thread, process, and machine boundaries. What do I mean by that? It means, for example, you can have safe interthread communication because you can send a message that will be delivered to an object and be delivered in another thread. or you can send a method to an object in another process, maybe even a process running on a different machine, and it will be delivered there.
The fundamental object in distributed objects is an NS connection, which runs from one NS port to another NS port, and the messages are sent across the connection. Now, one thing about NS port is that in abstraction there are different subclasses of NS port to refer to different transport mechanisms.
For example, there's one subclass that uses Mach messages for communication on the local machine. There's another subclass that uses TCP/IP for transport from one machine to another across the network. And depending on which subclass you use when you create your connection, you can get either means of transport.
And when you set up a connection, one side, which is going to be the server, sets one of its objects as the root object for the connection. It's vending that out. The other side, the client, gets a proxy for that object with its connection. And then it can send methods to the proxy as if it were sending them to the real object.
The methods are forwarded across the connection and delivered to that root object at the receiving end. and the way the two sides hook up also depends on what sort of transport mechanism you're using. If you're on the local machine, you can register connections by name. If you're going over TCP/IP, you usually rendezvous based on a TCP port and an IP address.
Now, there are a number of examples of this in the documentation on NSConnection. And exactly how you use it depends a little on what you're doing. But let me just give one brief example of a connection that's used for inter-thread communication. So, on one side, the main thread, what we're doing is first creating a port, and then we create a connection that we'll receive with that port.
We set ourselves, as it happens, as the root object for that connection. That means we're vending ourselves out. We're going to get the messages. And then we create another thread, and that other thread is going to send us messages on this connection. So we give it the port. Now, in that other thread, we use that port to recreate a connection to send to that port. and we do whatever calculation we want to in this thread. Maybe it takes a long time to do this calculation.
And then when we're done with that calculation, We ask this connection for the root proxy, and that gets a proxy for that root object, the self on the other side. And then we just send a method to it, server report result result. This normal Objective-C message then, except that in this case, it's going to be delivered to that other object in its thread, the main thread. So the result is safe inter-thread communication.
Okay, and I'd also like to talk about a few other things in Foundation that are enabled, although not immediately directly, by the runloop mechanism. So, NSURL in Foundation, the basic use of NSURL is to encapsulate a URL. So you can have the scheme and the path and all the other components of URL and analyze those and pass that around. But another thing you can do with NSURL is you can do simple fetching of the contents of URL by default built in for file colon and HTTP colon schemes.
And this is a rather simple mechanism and some limitations, but you can get notified when the download starts or when various interesting things happen during it. There's also a slightly more complicated mechanism if you want more detailed control over what's happening in NSURL. There's an NSURL handle that can give you somewhat finer control and you can also subclass this if you want to handle other schemes that you know how to handle.
Another thing has to do with Apple events. It's been mentioned earlier that Cocoa provides a lot of support for Apple script for scripting. But it's also possible to receive individual Apple events. It's very simple. There's a shared NSAppleEventManager, one object, and all you do is register a particular object and method to be called when a particular Apple event type arrives.
And then you'll be called with a selector, be given the Apple event, and then be given a reply. And then you fill in the reply and send it back. Very Okay, and finally, I'd like to talk a little bit about exceptions in Foundation. Now, the Objective-C language does not have a built-in exception mechanism, but the Foundation provides one. That is, an exception object, NSException, and a means of raising exceptions and a means of handling them. and these NS exceptions, they have a name, a string name that's used to identify them, and a reason, which is some reason that's supposed to be intelligible to a programmer.
and others. Now, in your own code, you can use exceptions however you like, but as Cocoa uses them, typically we use them only for really truly exceptional conditions, things that can't really be handled, usually the result of some programming error. We don't want you to have to use exception handling contexts all over the place, only in special cases. And, of course, they can be handled at multiple levels.
For example, typically the app kit will catch exceptions occurring in its main event loop if they are not caught at some lower level. If an exception really is not handled at all at any level, then there's a default exception handler that basically just exits the process or you can install your own if you want some other behavior.
So how do you raise an exception? The simplest way is by calling a class method on NSException to raise with a name. You give it the name of the exception and format, which is a printf style format string and arguments to produce the reason, which is, as I said, supposed to be intelligible to a programmer. And there is a slightly more complicated way you have to do that. You can attach essentially arbitrary user info data to the exception. So if you want to do that, you can create the exception and then go ahead and raise it.
How do you handle an exception? The way you do it is, first of all, you start with an NSDuring, and then comes the block wherein you try to perform the operation that might raise an exception, an NSHandler, and then comes the exception handling context where you would be sent to if an exception was raised, and then NSHandler ends the block.
Now, once you get into this exception handling context, when an exception was raised, there are four ways you can get out. One is you can just fall through to the end, just keep going as if nothing happened. Or you can re-raise the exception that was raised, just send it on. Or maybe you have a new exception you want to raise that covers that. Or you can exit the method altogether. And there's an NSValue return that's used if you're returning something from the method, or an NSVoid return if the method returns void.
and the way that you know what the exception was that was raised is that there's a local variable whose context is this exception handling block, local exception. And you can take that and then save it if you want to use it later or possibly re-raise it. and let's see, the only other thing I wanted to mention about these exceptions is that in Java, they're wrapped as, I believe, a subclass of the runtime exception. And so next I want to turn the stage over to Chuck Pisula.
Okay, this is the section of the talk where basically everyone's on the same foot because we're talking about new features which even experienced people haven't seen before. So, I'm actually kind of lying a little bit because some of these new features are really things that we had before, hadn't been working for a while, and they're now back. So, let's get into these.
First of all, let's talk about XML. Until now, Cocoa used to store what we call plists in an ASCII format. We still store it in an ASCII format, but that format's defined using XML. And when we did this, we also added support for a number of types that developers have been asking for for a while. So we can now do things like array, data, date, some various other standard types that you want. And if you need to do anything that's not in the standard list, you can always convert to an NSString or an NSData.
Cocoa now also has support for dealing with HFS file types. Now, we added this support without modifying any of our API that uses extension-based parameters. So, for instance, if you want to bring up an open panel and tell it what types you're allowing it to open, you can pass in strings which represent HFS file types.
And, again, we've done this without modifying the API. So if you want to allow the Open Panel to open some sort of HFS file type. You'd use one of the functions like NSHFSFile for type code. You'd convert the OS type code to an NSString and pass that into the extension-based API. So you can mix extensions along with HFS file types.
NSWorkspace is back and mostly functional again. So there are parts that hadn't been functioning for a while. The parts that still aren't functioning are mostly OS specific. Those are the few exceptions. We've also added some new methods. Methods to open URLs, check whether or not something is a file package, and even methods to check for local mounted volumes.
We now have support for custom window shapes. The things you see like the clock up there were done using a custom window shape. And what you, the support that's needed to do this is the ability to first set the alpha value of a window. Tell a window that it's opaque, then what you would do is fill its content with clear color, and anywhere you fill it with non-clear color would then be the window. So in this example above, I initially told the window that it's not opaque, filled it with clear color, and then drew using a clock image, and then of course put the hands on top of it.
and we've also added support for you to turn off shadows. Now, if you do your own custom window shades, you're of course going to have to handle your own window dragging. We now have small controls. A number of controls that you're used to seeing in Cocoa come in both flavors, buttons and check boxes. Larger things, even like the tab view, like the example above, have normal and small variants.
To choose small controls, typically you're going to do it when you lay out your UI. So in Interface Builder, you're going to check one box that says use small control. But you can also do this programmatically by sending the set control size method using the small control size. Typically, the set control size message will be sent actually to the cell of the control. So those of you who are familiar with controls know that controls display using cells. And so the cell typically will be the one that receives this message.
and a status bar is back. It has no new API. Status items are really pretty simple. Sort of like the toolbar, they have many similar attributes. You can set a target action, a title, an image. You can associate a drop-down menu and they can have tool tips. And also similar to the toolbar, you can have your own custom views up there.
So if you want to install your own custom sort of status view, use the set view method. Typically, you want to make sure that the status items are small things and you should use them sparingly because there might not be a lot of space to display them. Currently, these things are displayed in the menu, in the top menu of Mac OS X.
Ennis MovieView is back. Ennis MovieView is a control in Cocoa that you can use to play QuickTime movies. It encapsulates a movie object, which is the QuickTime structure for movies. This movie object is now stored in an Ennis Movie and can be accessed from the Ennis Movie object if you want to do complicated things.
Also, the movie controller is stored by the Ennis MovieView. The movie controller is the little controls at the bottom that allow you to drag your position in the movie, press play or pause. You can access that directly if you want to do more complex things than Ennis Movie allows you to do.
As I said, NSMovie now wraps the QuickTime movie structure. However, it's not an Objective-C wrapper for all QuickTime APIs. So typically, if you need to do something specific with your movie, you'll access the movie directly and use QuickTime calls. You can initialize the NSMovie in a number of ways.
[Transcript missing]
Currently there's no support for allocating from a streaming type of source. If you need to do that, you should create your QuickTime movie object using new movie from DataRef and then hand it off to the NSMovie.
NSOpenGL has a couple new methods, in particular update and reshape. These are methods that those familiar with OpenGL programming know that if, say, the size of your viewport changes, you need to update certain viewing parameters. This is where you'll do that. Another note of interest, if you're doing full screen OpenGL applications, In order to prevent the dock or possibly the application menu from receiving mouth clicks or other things potentially, you might need to provide a cover window.
What you would do is make a window and give it a window level which is higher than anything else so that it would intercept the mouse events. And the window level you want to give it is KCG overlay window level. Okay, the toolbar is a completely new class. It comes along with a NS Toolbar item class which is also brand new.
The basic idea here is that the toolbar represents the NS Toolbar represents the whole toolbar, and it takes care of a number of tasks for you, like synchronizing toolbars. If you make a change in one toolbar, you want it to be reflected in all other toolbars with the same identifier. Again, Mail has three different kinds of toolbars, so if I change the ordering of my items in my Compose window, I want it to be reflected in any other Compose window I currently have up immediately.
NS Toolbar also takes care of archiving the configuration out to disk and making sure when you create new toolbars, they come up with that same configuration. In addition, NS Toolbar also will run the customization sheet that you've seen drop down from Mail and will control the display of that. All you need to typically do is provide those delegate methods that if you're in the last session you heard about.
Each item in the toolbar is represented by an NSToolbarItem object. Again, this is very similar to status bar items. They have some standard attributes like images, labels, menus that can be associated when you're in text-only mode. And they have, again, target and action because target and action is typically how controls communicate in Cocoa.
And again, if you need to provide your own kind of item that's not simply a sort of standard button, something like the search field in Mail can be provided as a custom view. Now we don't, in Cocoa again, we give you lots for free, so we also have some standard items that you can get for free. A separator toolbar item, one that will pop up the color panel, and so forth.
and a stepper is a new class. It's these small up and down arrows that you see here. And Basically something that you'll use if you want to have an incrementer. And you can set things like a min and max value, the increment step size, and whether it wraps or auto repeats.
NS Image has a couple new methods. And the reason that we have these new methods is that existing methods in NS Image typically did not pay attention, respect the current transform. They simply blit the image to the screen. Now the new methods, drawAtPoint and drawInRect, will pay attention to the current transform. So if you want to do things like scale or flip your image, things like that. And the additional parameters that you see are for specifying the part of the source image that you want to draw to the screen. You don't have to use the whole image.
You could just use the whole image, you know, 0, 0 to width by height. And then the remaining parameters are the operation. You can specify a simple copy type of compositing operation or a source over, so on. And the fractional amount of the image that you want to draw. So it can be anywhere from 0 to 1. 1 being fully opaque, 0 being fully transparent.
There are a couple new graphics features that we have that provide you finer control over some of the display operations. In particular, you can turn on and off anti-aliasing, and you can control the granularity of image interpolation. And the types of values that you can use for image interpolation are either none, low, high, or Cocoa's default.
and this bitmap image rep also has some new support for using color sync data. And the particulars of this, and others. So, let's go like this. NSBitmap Image Rep has a dictionary of sort of arbitrary information that can be attached to it. One piece of information that can now be attached to it is this color sync information.
And the color sync information is simply an NSData object and the key that you use to attach it is NSImage color sync profile data. If you look at the NSBitmap Image Rep documentation, you'll see that there's this business about properties that can be associated with the Bitmap Image Rep.
OK, so we shipped Mac OS X 10.0. Now we have to worry about things like versioning. So this is new in that sense, but we've always sort of had versioning. The important thing here is always test your applications against old versions of the AppKit and old versions of Mac OS X. And you may potentially need to check against what version number of the Cocoa frameworks you have. And the value you'll need to check is this value called NSAppKitVersionNumber. For 10.0, the version number of the Cocoa frameworks or AppKit sometimes we refer to it. The version number of AppKit was 577.0. Foundation would have its own version number.
and in 10.0, we didn't declare the variable anywhere, so you're going to have to make sure you declare it yourself if you want to reference it. And it's a double, so you declare extern double NSAppKit version number. And the important thing here is that when you're checking for, say, a new bug fix, we may have said the bug fix for Super Widget A came out in the next release of the AppKit.
And you don't want to check for greater than or equal to, well, greater than 577 to know whether or not the fix is there. Because the next major release may be 587. And this bug fix may have come along somewhere in between, say, on a software update even. You want to make sure that you compare against the specific number of where that fix is, because you want it to work on the in-between releases, not just... and others.
The first thing I want to talk about is the bug fixes. It's sort of hard to explain, but there would be a window where if you're just checking greater than 577, where the fix is not actually there, but you thought it was. So you want to check against specific version numbers. For bug fixes or features, in fact, that can be solely described by whether or not an object has a method, through the beauty of Objective-C's very fast introspection, you can actually just ask whether or not the object responds to the method.
If the object responds to the method, well then the feature's there. For all these things, check the release notes and it should be clear what you need to use for any particular situation. Finally, we have the slide you've seen many times, documentation. There's release notes. You should always look to see, of course, when those bug fixes were put in, what potentially what behaviors changed, overview documentation, so on and so forth.
and others. Example code, again, you've probably seen this many times, I'm just going to flip through. The roadmap, well basically you've missed it all except the feedback form. However, you've got the DVDs. If you haven't seen the Cocoa Review Talk and you're new to Cocoa, you should check that out.
The Using Cocoa Talk, those of you who weren't here the previous hour really missed out. It's full of lots of great demos. And the feedback form, so if you have anything to say, come to that tomorrow. Finally, Heather is always your person to contact. We have a feedback address if you have comments or suggestions. And I'd highly recommend subscribing to Apple's new Cocoa Development List.