Posts tagged Sample Code

Custom Drawing Using drawRect, Part 1

One of the more advanced techniques for creating custom user interfaces on the Mac is the use of NSView’s drawRect method.  Many answers to questions on StackOverflow and Apple’s mailing lists include recommendations to “just override drawRect and do the drawing yourself”.  Some folks see this recommendation and their eyes glaze over, thinking that it’s too advanced of a technique for them to wrap their heads around.  Over the next few days I’m going to go over some basic techniques that can yield powerful results.

Let’s start by setting up the Xcode project that will be the basis of the rest of these posts.

  • Open Xcode and create a new Cocoa Application project called DrawingSample.
  • Create a new NSView subclass called CustomDrawingView.
  • Open MainMenu.xib, add a new Custom View to the Main Window, set its class to be CustomDrawingView, and set it’s autosizing flags as seen here:

DrawingSample IB Layout

Save and Quit Interface Builder and switch back to Xcode.  Open CustomDrawingView.m, it should look like so:

@implementation CustomDrawingView
 
- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code here.
    }
    return self;
}
 
- (void)drawRect:(NSRect)dirtyRect {
    // Drawing code here.
}
 
@end

We’re going to start (and finish) today with just a simple concept and some basic drawing that will set the stage for the future posts. All drawing in Cocoa is done by first setting up the environment in which you want to draw, and then doing the actual drawing. For instance, if we want to draw a blue box, we first have to setup the color blue, define the bounds of the box, and then draw it.  In this case we are using the NSRect that is passed to the drawRect method as the box we want to draw, and we setup the color blue by calling [[NSColor blueColor] set].  We then use the convenience method NSRectFill to fill the dirtyRect with the color blue.  Notice that we didn’t pass the color to NSRectFill, we set it, and from then on anything we draw will be blue until we change the color.

You can think of drawing in Cocoa much the same way as you would think of painting with a brush.  You dip your brush in a certain paint color, paint the shape you want to paint, and then dip your brush in a new color and paint some more.

- (void)drawRect:(NSRect)dirtyRect {
	[[NSColor blueColor] set];
	NSRectFill(dirtyRect);
}

The preceding code, when run, will generate a view that looks like this:

NSRectFillNow, this may not look like much, but in future posts we will build on these concepts and, hopefully, by the end have drawn some pretty cool and useful things.

Core Data Code Generation

Bill Dudney has a great post about using categories to avoid some of the work when generating and regenerating classes from your Core Data model.  Read about it on his blog, PrEV, here: Core Data Code Generation.

Your New Friends: Obj-C Associated Objects

Andy Matuschak has posted a little-known feature of the Objective-C API under Snow Leopard on his blog.  I can’t think of a use for associated objects at the moment, but there’s a good chance that I will need them in the future.  You can read about them at his blog: Square Signals : Your New Friends: Obj-C Associated Objects.

UIView Manipulation Made Easier with a Category

I was watching a presentation recently where the presenter showed the header for a category that he had added to UIView to make his life a little easier. The point of the talk did not center around the category so I never saw much more than the header, but that was all I needed to recreate it for my use. Here’s the header:

#import <uikit/UIKit.h>
 
@interface UIView (MFAdditions)
 
- (id) initWithParent:(UIView *)parent;
+ (id) viewWithParent:(UIView *)parent;
 
// Position of the top-left corner in superview's coordinates
@property CGPoint position;
@property CGFloat x;
@property CGFloat y;
 
// Setting size keeps the position (top-left corner) constant
@property CGSize size;
@property CGFloat width;
@property CGFloat height;
 
@end

As you can see there isn’t a whole lot to this category, but if you’re doing a lot of view manipulation the benefits of it will rapidly become clear. There was one sticky wicket that I hit when implementing this class and it centers around this method:

+ (id) viewWithParent:(UIView *)parent;

When I first implemented this method I wrote it like so:

+ (id) viewWithParent:(UIView *)parent {
	return [[[UIView alloc] initWithParent:parent] autorelease];
}

This was all well and good as long as the only class that I was creating was a UIView, but I ran into trouble when I started creating UIImageViews. Instantiating new UIImageViews worked fine, but as soon as I called a UIImageView-specific method the app would crash:

*** -[UIView setImage:]: unrecognized selector sent to instance 0xd1b350

I struggled with the answer to this one for a while and it wasn’t until I presented my problem to the local CocoaHeads group did I get it all figured out. Here’s the correct way to write this method:

+ (id) viewWithParent:(UIView *)parent {
	return [[[self alloc] initWithParent:parent] autorelease];
}

By calling self instead of strongly typing the returned object as a UIView the class would dynamically determine the correct type at runtime.

You can download this category here: UIViewAdditions

NSNotification & NSNotificationCenter

Below you will find the slides and accompanying sample project that I presented at the January 2008 CocoaHeads meeting in Syracuse, NY.  I posted both the Keynote presentation and the PDF export of said presentation.  Because it was an informal gathering I decided to use a few of the Keynote transitions that are fun, but maybe a little over the top.  If this kind of thing bugs you, rock out the PDF version, it just has the slides.

Also, during the meeting a few folks asked about playing sounds and doing speech synthesis, so you will see simple examples of those technologies used in the sample project as well.

NSNotification and NSNotificationCenter (zipped up Keynote version)
NSNotification and NSNotificationCenter (PDF version)

Sample Project