We got rid of our 17-year old Macintosh LC yesterday. It was an absolute beast of a machine, with a 16 MHz 68020 processor, 4 Mb of RAM and a 40 Mb HD (and cost a rather unbelievable £1727 back in 1990 — including a 12-inch colour monitor, ImageWriter II and MacWrite II). My dad used it for word processing and a bit of Tetris right up to when its power supply packed up a couple of weeks ago. I think this was mainly because it booted in 19 seconds, which is marginally faster than my MacBook Pro! Check these out:
That’s what 512 Kb of VRAM (top) and 1 Mb of RAM looked like in 1990. Amazing how things progress…
Monthly Archives: April 2007
Why Leopard is taking so long
As we learnt yesterday, the release of Leopard will be delayed until October (i.e. 4 months after the end of “Spring” when it was originally slated to ship). Along with this news, developers also received a further development build of Leopard, 9A410, which, according to AppleInsider, ships with a list of almost three-dozen known issues, which are listed here. For the purposes of this post, I’m going to ignore the one or more “top secret” features that are supposed to appear in the final Leopard release and talk about why I think Leopard is taking so long, based on what we know (with a sprinkling of what we think we know)…
What Leopard will bring
Unless Leopard goes the way of Vista and drops support for any of the massive headline features, there will be a huge number of technically-challenging changes in Leopard that push Mac OS X even further ahead of its competitors. So let’s have a look at some of the major ones…
Objective-C 2.0
Welcome to Cocoa 2.0. Objective-C is receiving an overhaul in Leopard. This is not a minor undertaking by any stretch of the imagination. The greatest change is the introduction of garbage-collection, which frees developers from the tedium of manual memory management. Also being added to Obj-C is fast iteration (allowing, for example, traversal of an NSArray without first obtaining an NSEnumerator). Basically, this will reduce this code:
NSEnumerator *enumerator = [myArray objectEnumerator];
NSString stringFromArray;
while (stringFromArray = [enumerator nextObject]) {
NSLog(@"Array content: %@", stringFromArray);
}
to this:
for (NSString *stringFromArray in myArray) {
NSLog(@"Array content: %@", stringFromArray);
}
Nice. Rather brilliantly, Obj-C 2.0 will also introduce “declared properties”, which removes the need to explicity declare methods to access and set properties of your objects. Instead, one simply declares the name of the property and whether it is read-only or also supports writing. Accessing these properties will also be made extremely simple. This:
NSString *name = [myObject getName];
will become, with an appropriate change of the accessor method name, the considerably more readable:
NSString *name = myObject.name;
These changes are very welcome and if, for some reason, you’d rather not use them in your app, they are all opt-in — the Obj-C 2.0 compiler is backwards compatible with Obj-C. So how could this cause a delay in Leopard? I would (perhaps naïvely) imagine that Apple has opted-in to the Obj-C 2.0 runtime for at least some of its programs. We know, for example, that XCode 3.0 takes advantage of garbage-collection. I imagine that, upon rewriting a program to utilise garbage-collection, there is a lot to potentially go wrong, as old memory management code is removed and handed over to the garbage-collector. It’s also possible, although virtually inconceivable at this stage in development, that a problem was detected in the garbage-collector.
Pervasive 64-bit
This is another huge change. 64-bit programs run just fine in Tiger — as long as they’re confined to the UNIX layer. Any UI work had to be either CLI only or through a 32-bit wrapper GUI that communicated with the 64-bit backend. This has all changed in Leopard, which brings LP64 (64-bit Longs and Pointers) support to all application frameworks (except for QuickDraw, Sound Manager and the low-level Quicktime APIs, all of which have been deprecated). Not only this, but there is no 64-bit “mode” in Mac OS X as everything is completely backwards compatible. Programs, frameworks, scripts and even drivers may intermingle with one another, utilising either 32- or 64-bit registers on either PowerPC or Intel processors. Quite an achievement, especially 32-bit driver compatibility, which is something that Windows 64-bit hasn’t yet managed to master.
Why might the addition of pervasive 64-bit frameworks have slowed down Leopard development? Well, adding 64-bit support to all the application frameworks while maintaining backwards compatibility isn’t quite as straightforward as substituting all your ints for longs. Apple has been rather cunning about this whole affair and introduced NSInteger and NSUInteger (U for unsigned) and done the following:
#if __LP64__
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
Then they’ve gone through and replaced all unsigned ints with NSUInteger and all ints with NSInteger. Incidentally, they’ve also switched floats to doubles when running in 64-bit which, in the true spirit of “64-bitness”, greatly increases floating point accuracy. This switch is a very good thing, as Cocoa relies on floats for pretty much all of its graphical calculations (distances, colours, etc.). This is all pretty smart, but despite this, there’s still a huge amount of work to do in making sure that all the frameworks are good-to-go and optimised for the appropriate architecture. As a quick example… if you were using this:
NSLog(@"This used to be an int: %d", myInteger);
would you really want to change it to this:
NSLog(@"This is now a long: %ld", myLong)
or just leave it as it was? Take this fairly easy decision and multiply it by the number of times you think integers are used in all of Apple’s application frameworks. I would wager that’s quite a few times. Then there are the considerations about using 64-bit values in applications in more persistent places like Core Data where, more often than not, you don’t really need to store values in 64-bit data types and to do so would just be a waste.
Window Server (resolution independence and Spaces)
Another fairly massive change in Leopard is the introduction of a fully resolution-independent graphics engine. This is no small achievement — Apple isn’t expecting developers to be ready for this until 2008. Resolution independence has become necessary as the resolution of displays has increased considerably since the days of 72 dpi screens and will only continue to increase. Resolution independence removes any assumptions about the resolution of the display. If Tiger were running on two different 17″ monitors, with resolutions of 72 dpi and 144dpi, the interface on the 144 dpi screen would be half the size of that on the 72 dpi screen. This is not the desired effect — it would be preferable for the interfaces to be the same size, but revealing more detail on the 144 dpi screen.
Therein lies one of the difficulties with resolution independence — revealing more detail. In many cases, this is detail that just isn’t there at the moment, as applications tend to use fixed-size bitmap images (just look inside the iLife app bundles for evidence of this). In terms of why this is taking so long, I’d say it’s self-evident: new artwork is required for every icon and custom button in the whole operating system. In each case, Apple may have decided to use vector images or a series of NSBitmapImageReps at different sizes (1x and 4x if they’re taking their own advice).
But there’s not only this massive task to contend with, there’s a lot of altered code as well. As a slightly esoteric example, NSOpenGLView has had to be updated, as OpenGL draws everything in pixels, so the view has to perform an inverse transform on the bounds of the view to convert from pixels to points (which is the coordinate system of the view).
Then there’s Spaces, allowing for multiple desktops, which certainly relies upon Core Animation, but I imagine implementing Spaces also resulted in a non-trivial change to the window server, especially considering the ability to drag windows from desktop-to-desktop from an Exposé-like “show all desktops” view:
Spaces also allows for applications to be “bound” to a desktop, and the Dock (…or LaunchServices or both) is aware of these bindings, such that it will switch to the correct desktop when switching to a different application.
QuickTime and QTKit
QuickTime is receiving a massive overhaul in Leopard as well and QTKit is being pushed forward from its current, rather limited implementation in Tiger. Apple’s also introducing the QTKit capture APIs, which look very sophisticated, allowing simultaneous video capture from multiple USB and FireWire cameras and also simultaneous recording out to multiple devices. More significantly than this, the QuickTime low-level engine is receiving a complete revamp. The goals Apple set themselves for QuickTime in Leopard involved making all QuickTime code parallelisable and 64-bit clean with no remaining QuickDraw code and a code reorganisation to comply with the MVC. Again, this is a huge amount of work, especially as the old QT engine will remain in place (as well as the new one) for compatibility reasons.
Also, although it’s not quite as major, the QT browser plug-in is being given the option to render synchronously in the browser’s paint-loop. This is especially interesting considering the introduction of “alpha” H.264 — H.264-encoded video with an alpha-mask (apparently this is an optional part of the H.264 codec). As another brief aside, QuickTime is also adding support for the display of CEA-608 closed captioning text.
Text handling
Very little information has been released on this front, but the CoreText framework is being made public and Allan Odgaard (developer of TextMate) is excited. This is a big deal. I imagine that CoreText will consolidate some of the powerful features of NSTextStorage, NSLayoutManager, NSTextContainer, NSTextView and make understanding all of this:
a lot easier. This might not seem like a big deal, but there’s a lot of buzz surrounding this new API and, as such, I imagine Apple will be using it in a lot of places, again taking time to make sure it’s perfect (and yes, I know it’s been tested for a long time in Tiger, but expanding it OS-wide still isn’t easy).
Spotlight
Spotlight’s getting a bit of a revamp as well, allowing searching of networked machines, the use of boolean operators in searches, linking in to the system-wide dictionary to look up search terms and linking in to web search. Spotlight is also now being leveraged by the help system, revealing menu items based on the user’s query in the Help menu.
I don’t know how much under-the hood work is going on in Spotlight for Leopard but, on a side note, Uniform Type Identifiers are being made ubiquitous throughout Cocoa with the introduction of LSItemContentTypes and associated methods. NSWorkspace, NSDocumentController, NSPasteboard, NSOpenPanel and NSSavePanel (amongst others) are being overhauled to support this with new methods being added to NSWorkspace and NSDocumentController. Also, just to produce some example code for all of these changes, Apple has (finally) updated TextEdit to support NSDocument.
Core Animation
The introduction of this framework relies on three technologies already present in Tiger: Quartz, OpenGL, and Core Image. Core Animation is a “layer-based animation system” (formerly code-named Layer Kit), which allows for developers to rapidly add animation effects to their interfaces. It is utilised by Spaces and Time Machine as well as any application that is taking advantage of the new Image Kit or NSGrid views in Leopard. NSGrid views automatically add implicit Core Animation-fuelled animations when reordering, filtering, adding or removing items.
Layers in Core Animation support a variety of attributes and modes, including geometry (allowing 3D transforms), fills, sublayers, borders, CI filters, shadows, opacity, compositing and masking. This, as you can probably imagine, allows for some very complex scenes to be built and animated such as Apple’s now famous “city of album covers” animation. I’m not sure just how long implementing this kind of framework would take, but I’d guess that it wasn’t that easy.
Time Machine
Time Machine is Apple’s new automated backup solution. Conceptually, this is implemented by backing up read-only HFS+ snapshots of the entire file system at a frequency set by the user. So if you want to retrieve a file that was deleted yesterday, Time Machine is able to “point” the application from which the file was deleted to the file system snapshot from the day before yesterday.
Obviously this is only how it works conceptually — only the first backup is actually complete. After this, there is a low-priority back-up daemon that registers to observe file system events. As files change, the daemon notes the changes and coalesces them into one snapshot per day. For files that haven’t changed between snapshots, these snapshots use hardlinks to link to those files in the original backup (or the previous snapshot). This maybe isn’t quite as sophisticated as switching everything over to ZFS, which supports snapshots natively, but I still think there’s a lot of work in there.
And then there’s a whole lot more, including:
- PDFKit, which makes provision for adding, removing and reordering pages to PDFs with no code.
- Upgrade to CUPS 1.2, adding a massive number of new features, including a new web interface for printer administration.
- The implementation of ZFS (although I’m not sure of the extent of the implementation)
- Calendar Store is being added to allow developer access to view and edit user’s iCal events (and To-Do items).
- Multithreaded OpenGL engine and an upgrade OpenGL 2.1 and OpenGL ES 2.0.
- Support for animated desktops using Quartz Composer (which will also support custom patches in Leopard).
- Core image enhancements, including automatic UI generation for CI filters (!) and RAW processing.
- The introduction of Image Kit, including the new Image Browser view (presumable built on the new NSGrid class), the picture-taker panel with support for CI filters, a revamped slideshow view built atop Core Animation, built-in support for image rotation, cropping, scaling, image effects (like those currently in iPhoto) and saving out to multiple formats, etc…
- Massive enhancements to XCode and Interface Builder, such as in-line error messages in the editor and the ability to edit NSToolbars directly in the .nib file. There’s the introduction of XRay, which looks like an incredible tool for monitoring the performance of applications and finding any bottlenecks. And finally, Dashcode will be bundled with Leopard for rapid development of Dashboard widgets.
With a few exceptions, I’ve thus far completely ignored any updates to user-level applications and focussed on the under-the-hood changes in Leopard. I’m not going to go through the changes to applications at this time, but from a combination of Apple’s website and various leaked development-build screenshots, we know that iCal, Mail, iChat, PhotoBooth, Preview, Terminal, Automator, Safari and DVD Player have all undergone very significant upgrades. This has presumably taken quite some time as well…
Additionally, there are many changes to system-wide user-level features, such as the introduction of more sophisticated parental controls, greatly enhanced VoiceOver (with Alex the new voice designed for rapid screen-reading), a revamped Sharing preference pane and (somewhat inconsequentially) a whole slew of new screensavers.
And that, ladies and gentlemen, is just a small part of the reason why Leopard is taking so long…
Wrestling with OO
Until a week ago, I had never programmed in Objective-C or used any of Apple’s frameworks, APIs, “Kits” or otherwise. Furthermore, I had never done any object-oriented programming (OOP to its friends) or used XCode to any great extent. My only “real” programming experience was in Pascal (through Delphi) on Windows, a little bit of ANSI C and bits of Applescript, PHP and Python scripting for various purposes. This inexperience meant that I’d also never dealt with memory management thanks to either garbage collection or the simplicity of the programs I was writing. Now, however, I’ve written a Mac OS X native “Cocoa” program that does this:
Brilliant. It even resizes smoothly. But why and how did I do this and does it actually do anything useful?
Why?
I thought it would be a good idea to write a program to help me map out plasmids for my (limited) studies in biochemistry. Plasmids (as you may have just discovered from Wikipedia) are circular pieces of DNA, which are frequently used in molecular biology to insert genes into bacteria to, for example, overexpress a gene for protein purification or amplify a DNA sequence for further cloning. Knowing what genes, promoter sequences, restriction sites and other mysterious bits are in your plasmids is very important. So, I thought, I’ll finally get to grips with Cocoa and Objective-C and write a program to manage a library of plasmids.
How?
Where to start? For some reason, I found (and still find) the concept of object-oriented programming very daunting. I also find Objective-C a very intimidating language, despite it being just a “thin layer” above ANSI C (or, to be more technical, a “strict superset of C” — thanks, Wikipedia). I think I understand the basic principles of it – you write a class which acts as a prototype for instances of that class (of which there may be one or more). Each instance combines data (in instance variables) and methods to access and manipulate that data.
Furthermore, there’s the Model-View-Controller (MVC) architecture to contend with. MVC (admittedly very sensibly) advises that the user interface code and data manipulating code should be separated with a controller in the middle to mediate communication between the two. MVC took me a while to get my head round, until I realised that it’s just like any web application. HTML, CSS and Javascript make up the View, server-side scripts comprise the Controller and the database is the Model. Somehow the client-server divide clears things up for me there…
Anyway, once I’d thought about these new concepts for a bit, I realised that I still had no idea how to actually implement them. For example, how do you actually make a class? Then how do you make an instance (or multiple instances) of that class and, most importantly, just how on earth do things work from then onwards? These are not small questions. I’ll answer a couple of these questions here, just in case a beginner (like me) stumbles across it and finds it useful:
How to make your own class
While it’s technically possible to create your own class from scratch, it’s much easier to leverage a great feature of OO programming called subclassing. Creating a subclass allows you to inherit the behaviour of the class that you’re subclassing (known as the superclass) and then add or modify that behaviour as you see fit. There are two very straightforward ways to create a subclass, depending upon which class you feel fits your needs best:
1. The first way (which can only be used when subclassing NSView, NSDocument or NSWindowController) is to go to File > New File… in XCode and select the appropriate subclass from the “Cocoa” section of the dialog. This will create both the .m and .h files in your project with very little fuss.
2. The second way is to head to Interface Builder and right-click on the class you want to subclass in the Nib-file window, as shown here:
When you select this, a new class, titled “MySuperClassName” appears in the column to the right of the superclass. Right-click on this class, choose “Create files for MyObject”, check the right files are going into the right XCode project and then click “Choose” on the sheet.
Once the files are in place, you can then add the appropriate method and protocol declarations in the .h file and the implementation of these in the .m file. The above methods of subclassing are really just a convenience feature — the real magic involves just sticking this in MYClassName.h:
@interface MYClassName : NSObject {
}
…where MYClassName is a subclass of NSObject. Simple as that.
How to “instantiate” (make an instance of) your class
My OO-beginner roots are about to shine through now; if I’m honest, I’m still not sure what happens at this point, so read on with caution… To actually create an instance of your class, you must use the common Objective-C alloc and init calls as follows:
classInstance = [[MYClassName alloc] init];
First of all, this allocates memory for the instance of MYClassName, initialises its instance variables and then allows this instance to be referred to using “classInstance,” where classInstance was declared at the beginning of the .m file as follows:
MYClassName * classInstance
So I can now pass messages to the instance like this: [classInstance setColor:[NSColor greenColor]], which might turn classInstance green, for example. There is another way to do this, which is to declare classInstance inline as type “id”, which allows the Objective-C runtime to determine which class classInstance is an instance of dynamically (if that made any sense). This would be done as follows:
id classInstance = [[MYClassName alloc] init];
with no need to define classInstance at the beginning of the source file. However, I don’t know whether or not this makes any sense for my purposes…
Rather importantly, there are all sorts of memory management shenanigans that come along with creating instances of objects. These shenanigans include releasing objects when you’re finished with them (or autoreleasing them), which in turn involves such delightful activities as reference counting. I have to say that, at the moment, the prospect of thinking about the “implications of nested Autorelease Pools” (see page 27 of the next link) is very scary indeed. If you do want to know more about memory management on Mac OS X, Apple has some comprehensive documentation here.
Does it actually do anything useful?
Not really, no, but I’m confident that my trusty circle-drawing program will eventually become a functional thing of beauty. Honest. Anyway, I’ve just realised how long this post has become, so I’ll stop here and save some of my exciting adventures through NSBezierPaths, Core Graphics and Quartz for another post…