Sometimes it happens that Xcode throws you an exception, and you don’t know why. How do you print the relevant Exception information?

To get more information, you can configure the debugger to break when any exception is thrown. Go to the Breakpoint Navigator and click the little ‘+’-button at the bottom. Then click “Add Exception Breakpoint”.

Add Exception BreakpointBut, in many cases, even then you don’t get the information you wanted when the Exception occurs. Add these commands to the breakpoint configuration to show the name and reason of the breakpoint. This should get you on the way to eliminate the error.

Breakpoint on all exceptions

po [*(id *)($esp+4) name] and

po [*(id *)($esp+4) reason]

 

This works when you are using LLDB by printing the name and reason of the exception in the command window. You can also execute those commands in the command window, but you have to make sure to select stackframe 0 first.

If you are visiting here from Stackoverflow.com, welcome. Today some Moderator at StackOverflow decided to remove 4 or 5 of my answers, because they all contained a link to my blog.

May I promote products or websites I am affiliated with here?

Be careful, because the community frowns on overt self-promotion and tends to vote it down and flag it as spam. Post good, relevant answers, and if some (but not all) happen to be about your product or website, so be it. However, you must disclose your affiliation in your answers.

If a huge percentage of your posts include a mention of your product or website, you’re probably here for the wrong reasons. Our advertising rates are quite reasonable; contact our ad sales team for details. We also offer free community promotion ads for open source projects and non-profit organizations.

Indeed in the FAQ it says that that is not allowed. However my answers were tailored to the questions and were in each case a correct and useful answer. The link to my blog is because I don’t want to repeat myself, plus you cannot post screenshots easily in StackOverflow. If I spend 4 hours to write a detailed tutorial with lots of screenshots,  that answers relevant SO questions, I don’t see a reason why it is not allowed to link to it. My code is open source under MIT license. I don’t have a lot of advertisement on my blog. Hell, google adsense hasn’t paid out for more than two years now. I don’t even sell anything.

So in the future, I’m no longer posting to SO myself. If you find a relevant question on SO that one of my blogposts answers, you may ofcourse link to them.

kthxbye.

Lots of people seem to be having problems with designing and implementing easy to use and easy to maintain table view cells, for use in a UITableView on iOS. There is actually quite a nice way to make your life easy. In this article I’ll show the basic technique on how to do it.


We start with a new demo project, where we use the single view application template.
In this tutorial we will use the iPhone version, but the technique applies just a easily to iPad applications of course.

Let’s call the project StronglyTypedTableViewCell. In this project template we get a ViewController with a Xib file for free. Open the xib and add a table view to the view by dragging it in from the object library.

Link the UITableView to the file owner, by control-click-dragging from the table to the file owner twice. Once for the delegate, once for the data source.

We switch over to the code, and indicate in the ViewController, that is the file owner of the objects created visually in the xib file, that it conforms to the protocols required by the UITableView links: UITableViewDelegate and UITableViewDataSource. In the ViewController.h header file: change this line of code:

@interface ViewController : UIViewController
    <UITableViewDelegate, UITableViewDataSource>

We need to implement two required methods in the ViewController. We start with dummy implementation to get rid of the compiler warnings. So in ViewController.m write:

- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section
{
  return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  return nil;
}

The first method is called first by the UITableView to find out the total number of rows that needs to be displayed in a certain section. For this demo, we are not using sections, so we just return 1 for now. We don’t have any data yet.

The second method will then be called by the UITableView for getting the cell that needs to be displayed for the rows that are visible in the View. Normally this is only the first 12 rows, when you don’t change the row height.

Great. The skeleton for the tutorial is ready. Now we need to fabricate some data. Lets work with Cars for the tutorial. Let’s structure the code in a good object oriented way and add a new class to the project called Car. (Cmd-N, or File->New File) Select Objective-C class and give it the name Car.

For this demo, a car has two properties: The Make and the Type, both of type string. So in Car.h write:

#import <Foundation/Foundation.h>

@interface Car : NSObject

 @property (nonatomic, strong) NSString *make;  
 @property (nonatomic, strong) NSString *type; 

@end

and then in Car.m we complete the implementation section by synthesizing the implementation for those properties.

#import "Car.h"

@implementation Car

@synthesize make = _make;  
@synthesize type = _type;

@end

In the ViewController, we create a property to hold a number of cars. This property doesn’t need to be public, so we can write it in the private interface section in the ViewController.m file. This is called an “Extension”. Kind of like an anonymous Category in Objective-C.

@interface ViewController ()

@property (nonatomic, strong) NSMutableArray *cars;

@end

and again we synthesize it in the implementation section (ViewController.m):

@synthesize cars = _cars;

Now we can start by creating a couple of test objects to show in the cells of the UITableView. However, to make our code a little bit better, we will implement our own init method in the Car class. We start by defining the method in the public header Car.h:

- (id) initWithMake:(NSString*) make
               type:(NSString*) type;

The implementation is very straightforward, in Car.m write:

- (id) initWithMake:(NSString*) make
               type:(NSString*) type
{
    self = [super init];
    if (self)
    {
        self.make = make;
        self.type = type;
    }
    return self;
}

Among other things, this is a reason why we prefixed the name of the instance variable (ivar) that belongs with the property with an underscore. This way we have no conflict with the parameter names in this method.

Very well, now for the data. First import Car.h in ViewController.m, to make the class available. Next, in the viewDidLoad method of the ViewController, write (or copy paste ;-)):

    self.cars = [[NSMutableArray alloc]initWithCapacity:14];

    [self.cars addObject:[[Car alloc]initWithMake:@"Volkswagen" type:@"Polo"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"Ford" type:@"Mondeo"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"Mini" type:@"Cooper"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"BMW" type:@"X3"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"Audi" type:@"Q5"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"Renault" type:@"Wind"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"Chevrolet" type:@"Impala"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"Porsche" type:@"928"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"Lamborghini" type:@"Murchielago"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"Fisker" type:@"Karma"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"Nissan" type:@"Leaf"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"Toyota" type:@"Auris"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"Citroen" type:@"DS5"]];
    [self.cars addObject:[[Car alloc]initWithMake:@"Peugeot" type:@"205"]];

The preparations are complete. We can now show that data in the table. We change the implementation of the two methods to reflect the data we have. In the first method, we return the number of cars we have:

- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section
{
    return self.cars.count;
}

In the second, we return a standard UITableViewCell, to show the information about the car, for now we will just use one of the built-in Styles. We implement the reuse mechanism that UITableView supports. This way only 12 or so table view cells will ever need to be created, and we just reuse the existing ones, that fall off screen when the user is scrolling.

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // static string is only initialized once for this method.
    static NSString *reuseId = @"carCell";

    // try to reuse an existing table view cell.
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseId]; 

    if(nil == cell)
    {
        // if no cell is available for reuse, we create it, with the same reuseId.
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseId];
    }

    // next we customize the content of the TableViewCell

    // get the object we want to show:
    Car *car = [self.cars objectAtIndex:indexPath.row];

    cell.textLabel.text = car.make;
    cell.detailTextLabel.text = car.type;

    // return the customized cell
    return cell;
}

So far so good. This is the standard way of showing data in a UITableView. Nothing new. You can run the code on your device, or in the simulator.

Now we are going to create a custom cell, with a nice, typed API. Let’s get started.

We start by creating a new class called CarCell. This class will be responsible for encapsulating the Cell itself, and providing an easy to use API for our other classes. It inherits from the built-in UITableViewCell. Cmd-N or File-> New File. Select Objective-C Class and provide the name and super class. 

 

 

We will also create a Xib, because we want to visually configure the custom cell. Cmd-N or File -> New File. This time select User Interface, Empty Xib. Name it CarCell too.


In the xib file, drag a UITableViewCell from the object library into the design surface.Next, add two labels to the cell. Increase the height of the cell a bit, and make the first label bold text.

This is important: we are going to change the identity of the UITableViewCell. Make sure the Cell itself is selected and in the Identity Inspector, change the class to CarCell. Great. This way, when the nib is loaded, an instance of our CarCell will be created.

In the properties Inspector, also setup the reuse identifier for the cell. This should match the reuse identifier we use from code.

Now we can easily create two outlets, again visually. We need to open up the Assistant Editor, and make sure that the content of CarCell.h is shown there.

Next, Control-drag from the first label to the code in the assistant editor. It will prompt to create an outlet. Let it do it’s job and give it the name makeLabel. Do the same for the second label and call it typeLabel.

By doing this visually, all the necessary code has been generated for you by XCode.

Now we only need to be able to use the custom strongly typed cell in our table. That’s the tricky bit. Here, we need to change the file owner of the CarCell.Xib. Currently it doesn’t really have one. Select the file owner icon and open the identity inspector again, and change the class from NSObject to ViewController.

We will create an IBOutlet in the ViewController to easily get access to the CarCell object when it is loaded. So again, open up the Assistant Editor. Make sure that the content of ViewController.h is showing up and control drag from the CarCell itself into the code to create the IBOutlet. Call it carCellTemplate. Make sure it is a strong property.

Great. Now we can change the implementation of the second TableViewDataSource method to use our custom cell.
Start by importing CarCell.h into ViewController.h.

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // static string is only initialized once for this method.
    static NSString *reuseId = @"carCell";

    // try to reuse an existing table view cell.
    CarCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseId]; 

    if(nil == cell)
    {
        // if no cell is available for reuse, we create it, with the same reuseId.
        // instead of using a standard UITableViewCell style, we create our custom CarCell

        // load the objects in the nib, and setup the "file owner" to self
        [[NSBundle mainBundle] loadNibNamed:@"CarCell" owner:self options:nil];

        // at this point, self.carCellTemplate points to the CarCell that
        // was defined in the Xib.

        // so now we have a reference to it.
        cell = self.carCellTemplate;
    }

    // next we customize the content of the TableViewCell

    // get the object we want to show:
    Car *car = [self.cars objectAtIndex:indexPath.row];

    // we now have a typed api to customize our cell:
    cell.makeLabel.text = car.make;
    cell.typeLabel.text = car.type;

    // return the customized cell
    return cell;
}

We are almost done. If you run the project now, you will notice that cells are not shown correctly. This is because the height of the rows has increased.

That is usually the case when you design a custom cell. Therefore we need to get the height of the cell. You can read it from the designer. eg. 90px. And we need to implement one method in the ViewController. The tableview will ask it how high each cell needs to be. Notice that this method has to be very fast, because the TableView needs to know before doing anything how high the entire content will be to setup the scrollView.

- (CGFloat)tableView:(UITableView *)tableView
    heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 90;
}

We’re done. The result is not spectacular, but now you can easily start adding other user interface elements to the cell, without having to calculate or guess their positions.

In summary, what we did: Create a custom class CarCell that represents and encapsulates the cell. It is in that class that we define the API for manipulating and customizing the contents of our custom cell. Create the layout for that custom cell in a Xib, and make sure you manage the identity of the cell, so that it creates an instance of your custom class when loading the nib. Also make sure you have an easy way to access the objects created when loading the xib. We do this by changing the file owner of that new xib, and using an IBOutlet to get access to the objects we are interested in. Pay attention to setup the Reuse Identifier, otherwise it is not as memory efficient as it could be.

There is room for improvement. Instead of assigning to the properties of our cell when customizing it, we could have just assigned the Car itself (to a new property), and make our custom cell class responsible for showing that car in the setter of that property. This way we need less knowledge about the cell itself outside that class. Better applying the Single Responsibility Principle, and gaining in Cohesion of the objects.

There is a common pitfall here. You should no longer use any of the properties of the standard UITableView cell, as they will usually overlap with or hide the UI elements you added. Also, because these cells are reused by the UITableView, make sure to set all values that are visible to the user. If you forget some, you will see strange results, due to the caching and reuse of cells. You could provide a “prepare for reuse” method to facilitate this.

Fork the code on github or download a zip.

I hope this was useful. Any feedback is very much appreciated in the comments.

kthxbye!

In this article I will explain how to do face detection on a live video feed using an iOS 5 device. We will be using Core Image to do the heavy lifting. The code is loosely based on the SquareCam sample code from Apple.

To get started, we need to show the live video of the front facing camera. We use AVFoundation to do this. We start by setting up the AVCaptureSession. We use 640×480 as the capture resolution. Keep in mind that face detection is relatively compute intensive. The less pixels we need to munch, the faster the processing can be done. This is an interactive application, so realtime performance is important. We tell the AVCaptureSession which camera to use as input device.

To show the preview, we create an AVCaptureVideoPreviewLayer and add it to the previewView, that was created in the Xib. Don’t forget to call [session startRunning]. That was the easy part.

NSError *error = nil;
AVCaptureSession *session = [[AVCaptureSession alloc] init];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone){
    [session setSessionPreset:AVCaptureSessionPreset640x480];
} else {
    [session setSessionPreset:AVCaptureSessionPresetPhoto];
}
// Select a video device, make an input
AVCaptureDevice *device;
AVCaptureDevicePosition desiredPosition = AVCaptureDevicePositionFront;
// find the front facing camera
for (AVCaptureDevice *d in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
	if ([d position] == desiredPosition) {
		device = d;
        self.isUsingFrontFacingCamera = YES;
		break;
	}
}
// fall back to the default camera.
if( nil == device )
{
    self.isUsingFrontFacingCamera = NO;
    device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
}
// get the input device
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if( !error ) {

    // add the input to the session
    if ( [session canAddInput:deviceInput] ){
        [session addInput:deviceInput];
    }

    self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    self.previewLayer.backgroundColor = [[UIColor blackColor] CGColor];
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspect;

    CALayer *rootLayer = [self.previewView layer];
    [rootLayer setMasksToBounds:YES];
    [self.previewLayer setFrame:[rootLayer bounds]];
    [rootLayer addSublayer:self.previewLayer];
    [session startRunning];

}
session = nil;
if (error) {
	UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:
                        [NSString stringWithFormat:@"Failed with error %d", (int)[error code]]
                                           message:[error localizedDescription]
									      delegate:nil
							     cancelButtonTitle:@"Dismiss"
							     otherButtonTitles:nil];
	[alertView show];
	[self teardownAVCapture];
}

Now for the face detection.

We create the face detector itself in viewDidLoad, and keep a reference to it with a property. We use low accuracy, again for performance reasons.

NSDictionary *detectorOptions = [[NSDictionary alloc] initWithObjectsAndKeys:CIDetectorAccuracyLow, CIDetectorAccuracy, nil];
self.faceDetector = [CIDetector detectorOfType:CIDetectorTypeFace context:nil options:detectorOptions];

 

We access the data captured by the camera by creating an AVCaptureVideoDataOutput, using BGRA as pixelformat. We drop frames we cannot process. To do the actual processing, we create a separate processing queue. This feature works via the delegate method, that gets called for each frame on the processing queue.

// Make a video data output
self.videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
// we want BGRA, both CoreGraphics and OpenGL work well with 'BGRA'
NSDictionary *rgbOutputSettings = [NSDictionary dictionaryWithObject:
                                   [NSNumber numberWithInt:kCMPixelFormat_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
[self.videoDataOutput setVideoSettings:rgbOutputSettings];
[self.videoDataOutput setAlwaysDiscardsLateVideoFrames:YES]; // discard if the data output queue is blocked
// create a serial dispatch queue used for the sample buffer delegate
// a serial dispatch queue must be used to guarantee that video frames will be delivered in order
// see the header doc for setSampleBufferDelegate:queue: for more information
self.videoDataOutputQueue = dispatch_queue_create("VideoDataOutputQueue", DISPATCH_QUEUE_SERIAL);
[self.videoDataOutput setSampleBufferDelegate:self queue:self.videoDataOutputQueue];
if ( [session canAddOutput:self.videoDataOutput] ){
    [session addOutput:self.videoDataOutput];
}
// get the output for doing face detection.
[[self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo] setEnabled:YES];

The actual processing happens in the delegate method, that gets called on the background. First the frameBuffer is created, we use all attachments that come with the captured frame for processing.  We add exif information onto the image, because we need to know which side is up. The actual face detection is done in the method [self.facedetector featuresInImage:ciImage options:imageOptions];

- (void)captureOutput:(AVCaptureOutput *)captureOutput
    didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
       fromConnection:(AVCaptureConnection *)connection
{
	// get the image
	CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
	CFDictionaryRef attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, sampleBuffer, kCMAttachmentMode_ShouldPropagate);
	CIImage *ciImage = [[CIImage alloc] initWithCVPixelBuffer:pixelBuffer
                                                      options:(__bridge NSDictionary *)attachments];
	if (attachments) {
		CFRelease(attachments);
    }

    // make sure your device orientation is not locked.
	UIDeviceOrientation curDeviceOrientation = [[UIDevice currentDevice] orientation];

	NSDictionary *imageOptions = nil;

	imageOptions = [NSDictionary dictionaryWithObject:[self exifOrientation:curDeviceOrientation]
                                               forKey:CIDetectorImageOrientation];

	NSArray *features = [self.faceDetector featuresInImage:ciImage
                                                   options:imageOptions];

    // get the clean aperture
    // the clean aperture is a rectangle that defines the portion of the encoded pixel dimensions
    // that represents image data valid for display.
	CMFormatDescriptionRef fdesc = CMSampleBufferGetFormatDescription(sampleBuffer);
	CGRect cleanAperture = CMVideoFormatDescriptionGetCleanAperture(fdesc, false /*originIsTopLeft == false*/);

	dispatch_async(dispatch_get_main_queue(), ^(void) {
		[self drawFaces:features
            forVideoBox:cleanAperture
            orientation:curDeviceOrientation];
	});
}

The last step is to actually draw something on the screen where the face has been detected. The method drawFaces:forVideoBox:orientation is called on the main thread to do this.

In this method, we will draw an image onto a CALayer in the previewLayer. For each detected face, we will create or reuse a layer. We have to setup the correct size based on the bounds of the detected face. Take into account that the video has been scaled, so we also need to take that factor into account.  Then we position the image onto the layer. The layer in turn needs to be rotated into the right orientation. This is done based on the device orientation.

// called asynchronously as the capture output is capturing sample buffers, this method asks the face detector
// to detect features and for each draw the green border in a layer and set appropriate orientation
- (void)drawFaces:(NSArray *)features
      forVideoBox:(CGRect)clearAperture
      orientation:(UIDeviceOrientation)orientation
{
	NSArray *sublayers = [NSArray arrayWithArray:[self.previewLayer sublayers]];
	NSInteger sublayersCount = [sublayers count], currentSublayer = 0;
	NSInteger featuresCount = [features count], currentFeature = 0;

	[CATransaction begin];
	[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];

	// hide all the face layers
	for ( CALayer *layer in sublayers ) {
		if ( [[layer name] isEqualToString:@"FaceLayer"] )
			[layer setHidden:YES];
	}	

	if ( featuresCount == 0 ) {
		[CATransaction commit];
		return; // early bail.
	}

	CGSize parentFrameSize = [self.previewView frame].size;
	NSString *gravity = [self.previewLayer videoGravity];
	BOOL isMirrored = [self.previewLayer isMirrored];
	CGRect previewBox = [ViewController videoPreviewBoxForGravity:gravity
                                                        frameSize:parentFrameSize
                                                     apertureSize:clearAperture.size];

	for ( CIFaceFeature *ff in features ) {
		// find the correct position for the square layer within the previewLayer
		// the feature box originates in the bottom left of the video frame.
		// (Bottom right if mirroring is turned on)
		CGRect faceRect = [ff bounds];

		// flip preview width and height
		CGFloat temp = faceRect.size.width;
		faceRect.size.width = faceRect.size.height;
		faceRect.size.height = temp;
		temp = faceRect.origin.x;
		faceRect.origin.x = faceRect.origin.y;
		faceRect.origin.y = temp;
		// scale coordinates so they fit in the preview box, which may be scaled
		CGFloat widthScaleBy = previewBox.size.width / clearAperture.size.height;
		CGFloat heightScaleBy = previewBox.size.height / clearAperture.size.width;
		faceRect.size.width *= widthScaleBy;
		faceRect.size.height *= heightScaleBy;
		faceRect.origin.x *= widthScaleBy;
		faceRect.origin.y *= heightScaleBy;

		if ( isMirrored )
			faceRect = CGRectOffset(faceRect, previewBox.origin.x + previewBox.size.width - faceRect.size.width - (faceRect.origin.x * 2), previewBox.origin.y);
		else
			faceRect = CGRectOffset(faceRect, previewBox.origin.x, previewBox.origin.y);

		CALayer *featureLayer = nil;

		// re-use an existing layer if possible
		while ( !featureLayer && (currentSublayer < sublayersCount) ) {
			CALayer *currentLayer = [sublayers objectAtIndex:currentSublayer++];
			if ( [[currentLayer name] isEqualToString:@"FaceLayer"] ) {
				featureLayer = currentLayer;
				[currentLayer setHidden:NO];
			}
		}

		// create a new one if necessary
		if ( !featureLayer ) {
			featureLayer = [[CALayer alloc]init];
			featureLayer.contents = (id)self.borderImage.CGImage;
			[featureLayer setName:@"FaceLayer"];
			[self.previewLayer addSublayer:featureLayer];
			featureLayer = nil;
		}
		[featureLayer setFrame:faceRect];

		switch (orientation) {
			case UIDeviceOrientationPortrait:
				[featureLayer setAffineTransform:CGAffineTransformMakeRotation(DegreesToRadians(0.))];
				break;
			case UIDeviceOrientationPortraitUpsideDown:
				[featureLayer setAffineTransform:CGAffineTransformMakeRotation(DegreesToRadians(180.))];
				break;
			case UIDeviceOrientationLandscapeLeft:
				[featureLayer setAffineTransform:CGAffineTransformMakeRotation(DegreesToRadians(90.))];
				break;
			case UIDeviceOrientationLandscapeRight:
				[featureLayer setAffineTransform:CGAffineTransformMakeRotation(DegreesToRadians(-90.))];
				break;
			case UIDeviceOrientationFaceUp:
			case UIDeviceOrientationFaceDown:
			default:
				break; // leave the layer in its last known orientation
		}
		currentFeature++;
	}

	[CATransaction commit];
}

There you go. That is the basic principle behind Face Detection in iOS 5. For the nitty gritty details, just have a look at the code on github or download the zip.

There is much more to be explored. Core Image also provides access to the detected location of eyes and mouth. That would be even better to place the mustache correctly. We could also rotate the image, based on the angle of the face on the screen.

Adios!

Any feedback is appreciated in the comments.