Saturday, December 22, 2012

Android NDK now includes clang with Objective-C support

Apparently, the Android NDK started including clang in ndk-r8c. The Google folk had always disabled Objective-C from their gcc ports, making Objective-C support that much more difficult to achieve, but I had a hunch that disabling Objective-C from clang may well have been more effort than it's worth.

I just tried it with a vanilla, freshly downloaded ndk-r8d and a small Objective-C program compiled without problems, so it looks like my hunch was correct.

Of course, it didn't link because there is no runtime, but providing one is a much smaller effort than reconfiguring the entire toolchain. After that, it gets interesting...

Update: after getting a runtime, it linked and ran on my Galaxy II test phone.

Wednesday, November 7, 2012

Cocoa / Objective-C performance course at Kloster Eberbach

Stefanie Seitz is organizing a Cocoa / Objective-C performance course at Kloster Eberbach, held by yours truly, December 9-12th.

I am sure it'll be fun and hope it will be instructive. If you're interested, give Stefanie a shout!

Update: December was a bit optimistic for all involved, so we're tentatively moving this out to the beginning of March. I'll post the exact date once it has settled.

Thursday, November 1, 2012

CGLayer performance and quality

The CoreGraphics CGLayer object seems to keep causing confusion. I hope I can clear that up a bit.

The intent of CGLayer was to have some sort of object for optimized repeated drawing, similar to how you would call a drawing procedure multiple times, have multiple instances of a view or simply draw the same PDF or bitmap image multiple times. The difference was supposed to be that the drawing layer could do secret magic "stuff" to optimize the repeated instance drawings. Not giving away the specific representation or optimizations performed means that whatever is done can be adapted both to different contexts and with changing technology.

Currently, that primarily means a texture stored on the graphics card, and that is and was one of the possible optimizations. However, the reasoning for such an opaque optimized object goes back further, at least to NeXTStep/Rhapsody: DisplayPostscript was implemented as a server process, and despite Mach's fast memory-remapping messages, shipping images back and forth between the client and server was not an optimization, and so you couldn't use (client side) bitmaps for optimized drawing. Well you could, but it wouldn't be optimized.

With Quartz becoming a client-side drawing library in Mac OS X, some of the reasons for these distinctions disappeared, but the distinctions (such as NSBitmapImageRep vs. NSCachedImageRep) remained. I think there were plans for CGLayer to become a kind of NSCachedImageRep on steroids, for example maintaining OpenGL display lists, but as far as I could tell, those plans never really panned out: in my tests drawing a CGLayer always looked the same as drawing a cached bitmap, and also performed similarly.

In 10.5, most of the accumulated cruft was cleaned up, NSBitmapImageRep for examples is now only a fairly thin wrapper around its underlying CGImage, and NSCachedImageRep was deprecated completely in 10.6, as it no longer has any advantages. With these changes, drawing a CGImage or a NSBitmapImageRep became as fast as possible, with CGImages stored on the graphics card. At this point CGLayer was essentially abandoned, and for drawing to the screen, you can just as easily use a NSBitmapImageRep, CGImage, UIImage etc.

So is CGLayer now completely useless? Not quite! It turns out that when drawing to a PDF context, CGLayer will generate a PDF Form object, which stores the original drawing commands (vectors, text, images). This is obviously much better than drawing a bitmap, both in terms of quality and in terms of file size and performance.

So if your plans include printing or generating a PDF, then I would recommend taking a look at CGLayer for repeated drawing of (vector) content.

Thursday, October 18, 2012

Little Message Dispatch, aka "Sending Primitives to the Main Thread"

Just ran across a Stack Overflow question on using primitives with performSelectorOnMainThread:. The original poster asks how he can send the message [myButton setEnabled:YES] from a background thread so it will execute on the main thread.

Alas, the obvious [myButton performSelectorOnMainThread:@selector(setEnabled:) withObject:(BOOL)YES waitUntilDone:YES]; is not only ugly, but also doesn't work. It used to kinda sorta work for scalar integer/pointer parameters that fit in a register, but it certainly wasn't a good idea and started breaking when Apple started to retain those parameters. Casting a BOOL to a pointer and back might work at times, sending it a retain will definitely not.

What to do? Well, I would suggest the following:



[[myButton onMainThread] setEnabled:YES];


Not only does it handle the primitives without a sweat, it is also succinct and readable. It is obviously implemented using Higher Order Messaging (now with Wikipedia page), and I actually have a number of these HOMs in MPWFoundation that cover the common use-cases:

@interface NSObject(asyncMessaging)

-async;
-asyncPrio;
-asyncBackground;
-asyncOnMainThread;
-onMainThread;
-asyncOn:(dispatch_queue_t)queue;
-asyncOnOperationQueue:(NSOperationQueue*)aQueue;
-afterDelay:(NSTimeInterval)delay;


@end

There is a little HOM_METHOD() Macro that generates both the trampoline method and the worker method, so the following code defines the -(void)onMainThread method that then uses performSelectorOnMainThread to send the NSInvocation to the main thread:
HOM_METHOD(onMainThread)
        [invocation performSelectorOnMainThread:@selector(invokeWithTarget:) withObject:self waitUntilDone:YES];
}

You can use MPWFoundation as is or take the above code and combine it with Simple HOM.

Monday, October 15, 2012

CoreGraphics, patterns and resolution independence (not just) for retina displays

In a recent post with followup, Mark Granoff demonstrates how to intelligently deal with the need for higher resolution backgrounds by using CoreGraphics pattern images, particularly using the [UIColor colorWithPatternImage:] method. However, he does wonder why he still has to deal with retina resolution issues at some points in the code, when "…the docs say that CoreGraphics handles scaling issues automatically."

That's a good question, and the answer lies in the fact that the example uses pattern images and mask images, rather than CoreGraphics patterns and geometric primitives. Once you explicitly ask for bitmap representations, you will be dealing with pixels and different resolution. The clue is to avoid going to pixels as much and as long as possible. The doughnut shape, for example, can easily be achieved using basic geometry and a little knowledge of the Postscript/PDF fill rules.

Using the standard "nonzero-winding-number" rule, a doughnut effect can be achieved by having the two arcs that are nested inside each other drawn in opposite directions. That's one of the reasons the extra "clockwise" parameter exists.


  NSPoint centerPoint = NSMakePoint([view frame].size.width/2, 150);
  [context arcWithCenter:centerPoint
           radius:50 
           startDegrees:0
           endDegrees:360  
           clockwise:YES];
  [context arcWithCenter:centerPoint
           radius:100
           startDegrees:0
           endDegrees:360  
           clockwise:NO];
  [context fill];

(The code examples here use MPWDrawingContext for convenience, pure CoreGraphics code tends to be two to three times more verbose). The second way to achieve the doughnut would be to just use the even/odd fill rule, in which case the direction doesn't matter. matter.

Patterns can also be specified geometrically, or rather with callbacks to draw the pattern shape. Objective-C Blocks are really a perfect fit for specifying these sorts of callbacks, but were only introduced much later than the CoreGraphics pattern callback API. The following code shows how to specify the diamond pattern via an Objective-C block, courtesy of some glue API provided by MPWDrawingContext.


        NSSize patternSize=NSMakeSize(16,16);
        id diamond = [context laterWithSize:patternSize
                              content:^(id  context){
            id red = [context colorRed:1.0 green:0.0 blue:0.0 alpha:1.0];
            [context setFillColor:red];
            [[context moveto:patternSize.width/2 :2] 
				lineto:patternSize.width-2 :patternSize.height/2];
            [[context lineto:patternSize.width/2 :patternSize.height-2]
				lineto:2 :patternSize.height/2];
            [[context closepath] fill];
        }];
        [context setFillColor:diamond];
        [[context nsrect:[[self view] frame]] fill];

The "laterWithSize:content:" message creates a callback object that not only encapsulates the block, but also implements a -CGColor method so the callback can be used directly as a color in -setFillColor:.

With all the graphics specified using pure geometry, CoreGraphics can now do its thing and automatically handle varying device resolutions, wether it's a retina display or a zoomable interface or even print, all without ever having to deal with the different resolutions in code. Although I haven't tested it, the code should also use less memory, because it doesn't create potentially large temporary bitmaps, and for the cherry on top it's also a fraction of the code. CoreGraphics rules!

Forked project on github.

Saturday, October 13, 2012

Time for an Objective-C web framework?

More good news for Objective-C weenies like myself from the programming language popularity front: since we last checked in January of this year, Objective-C has now not only leapfrogged C# (now 50% above!), but even managed to edge out C++ and maintain that edge for 4 months. Amazing times, especially for us stealth-marketing hardened NeXTies.

With Ruby now at about 20% of the Objective-C popularity ratings (whatever those mean), maybe there is room to extend the Objective-C stack to the web? Especially as we are experiencing a shift in technologies from MVC frameworks to REST backends.

After all, we had this in the past, with core object models bridged to the UI with AppKit, to legacy databases with EOF and to the web with WebObjects. Now we could do mobile, desktop and server with a common, well-tested object model. Some say crafting object models this way is a Good Idea™. Thoughts?

Tuesday, June 12, 2012

A Pleasant Objective-C Drawing Context

In a recent post, Peter Hosey muses On the API design of CGBitmapContextCreate and apparently finds it somewhat lacking. Apart from agreeing violently, I'd extend that not just to the rest of CoreGraphics, but really to the state of drawing APIs in OSX and iOS in general.

On OSX, we have the Cocoa APIs, which are at least somewhat OO, but on the other hand don't have a real graphics context, only the stunted NSGraphcisContext which doesn't actually allow you to do, you know, graphics. Instead we have a whole bunch of "use-once" objects that are typically instantiated, told to draw themselves to an implicit global drawing context and then discarded. This seems exactly backwards, I would expect an explicit graphics context that I can use to draw using a consolidated API.

That consolidated API is only available in the form of the CGContextRef and its associated functions, but alas that's a C API. So extremely long names, but without named parameters or useful polymorphism. Despite the fact that a graphics context is a quintessential example of OO, only Apple can create subclasses of a CGContext, and even then in only a sorta-kinda sort of way: CGBitmapContextCreate returns a CGContextRef that silently knows how to do things that other CGContextRefs do not. Same for CGPDFContextCreate.

On iOS, CoreGraphics is really your only choice, and double so if you want code that works on both iOS and OSX, but that means having to put up with the API, constantly converting between UI/NS objects and CoreGraphics and then there's the whole text mess.

Having been a great fan of algorithmic drawing every since my exposure to DisplayPostscript on the NeXT Cube, I found all of this sufficiently unsatisfactory that I decided to work on a solution, the first step of which is a lightweight drawing context that provides a reasonable Objective-C drawing API on top of CoreGraphics and works the same on OSX and iOS.

The result is on github: MPWDrawingContext, embedded in a version of Mark Gallagher's excellent IconApp AppKit drawing example. The same code is also used in the iOS target (a variant of Marcus Crafter's version of IconApp). I've also started using the context in a bunch of my own projects (that was the purpose after all) and so far it's made my graphics coding much more pleasant.

Another advantage, at least for me, is that bridging to scripting languages is automatic due to Objective-C's runtime information, whereas C functions have to have to be bridged separately and maintained, which is burdensome and doesn't necessarily get done.

At least one of Peter's problem with CGBitmapContextCreate is also solved: creating a bitmap context is as easy as

    [MPWCGDrawingContext rgbBitmapContext:NSMakeSize(595,842)]
Last not least: although it wasn't an explicit goal, there is also a pleasant reduction in code bulk.
LinesCharactersLines %Characters %
AppKit146659367.12%76.69%
CGContext134736773.13%68.63%
MPWDrawingContext985056--