Posts from the “iOS” Category

Debouncing Method Dispatch in Objective-C

I’ve been doing a lot of Node.js programming recently, and Javascript / Coffeescript programming style is starting to boil over into the way I think about Objective-C. One of my favorite practices in Javascript is the concept of deferring, throttling, or debouncing method calls. There are tons of uses for this. For example, let’s say your app is updating a model object, and you want to persist that model object when the updates are complete. Unfortunately, the model is touched in several bits of code one after another, and your model gets saved to disk twice. Or three times. Or four times. All in one pass through the run loop.

It’s pretty easy to defer or delay the execution of an objective-c method using “performSelectorAfterDelay” or any number of methods. Debouncing—running a method just once in the next pass through the run loop after it’s been called multiple times—is a bit trickier. However, in the case described above it’s perfect. Touch the model all you want, call “save” a dozen times, and in the next pass through the run loop, it get’s saved just once.

Here’s how I implemented a new debounce method “performSelectorOnMainThreadOnce”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@implementation NSObject (AssociationsAndDispatch)
 
- (void)associateValue:(id)value withKey:(void *)key
{
	objc_setAssociatedObject(self, key, value, OBJC_ASSOCIATION_RETAIN);
}
 
- (void)weaklyAssociateValue:(id)value withKey:(void *)key
{
	objc_setAssociatedObject(self, key, value, OBJC_ASSOCIATION_ASSIGN);
}
 
- (id)associatedValueForKey:(void *)key
{
	return objc_getAssociatedObject(self, key);
}
 
- (void)performSelectorOnMainThreadOnce:(SEL)selector
{
    [self associateValue:[NSNumber numberWithBool: YES] withKey: (void*)selector];
 
    dispatch_async(dispatch_get_main_queue(), ^{
        if ([self associatedValueForKey: (void*)selector]) {
            [self performSelector: selector];
            [self associateValue:nil withKey:(void*)selector];
        }
    });
}
 
@end

A more advanced version of this method would allow you to say “perform this selector just once in the next 100 msec” rather than performing it in the next iteration through the run loop. Anybody want to take a stab at that?

stringWithFormat: is slow. Really slow.

I’m working on a project that makes extensive use of NSDictionaries. Buried deep in the model layer, there are dozens of calls to stringWithFormat: used to create dictionary keys. Here’s a quick example:

1
2
3
4
5
6
7
8
- (CGRect)rect:(NSString*)name inDict:(NSDictionary*)dict
{
    float x = [[dict objectForKey:[NSString stringWithFormat: @"%@@0", name]] floatValue];
    float y = [[dict objectForKey:[NSString stringWithFormat: @"%@@1", name]] floatValue];
    float w = [[dict objectForKey:[NSString stringWithFormat: @"%@@2", name]] floatValue];
    float h = [[dict objectForKey:[NSString stringWithFormat: @"%@@3", name]] floatValue];
    return CGRectMake(x, y, w,h);
}

In this example, I’m using stringWithFormat: in a simple way. To read four CGRect values for the rect ‘frame’ from the dictionary, it creates the keys [email protected], [email protected], [email protected], and [email protected] Because of the way my app works, I call stringWithFormat: to create strings like this a LOT. In complex situations, to the tune of 20,000x a second.

I was using Instruments to identify bottlenecks in my code and quickly discovered that stringWithFormat: was responsible for more than 40% of the time spent in the run loop. In an attempt to optimize, I switched to sprintf instead of stringWithFormat. The result was incredible. The code below is nearly 10x faster, and made key creation a negligible task:

1
2
3
4
5
6
7
8
- (NSString*)keyForValueAtIndex:(int)index inPropertySet:(NSString*)name
{
        // the following code just creates %@@%d  - but it's faster than stringWithFormat: by a factor of 10x.
        char cString[25];
        sprintf (cString, "@%d", ii);
        NSString* s = [[[NSString alloc] initWithUTF8String:cString] autorelease];
        return [name stringByAppendingString: s];
}

It’s worth mentioning that I’ve refactored the app even more—to completely avoid saving structs this way (since NSValue is uh… an obvious solution), but I felt like it was worth posting this anyway, since you might not be able to refactor in the way I did.

iPhone Development Tutorial

I gave a presentation within the Engineering school on Friday that gave a brief look at the iPhone platform and Objective-C. The end of the presentation was a quick tutorial in Interface Builder and XCode. You can download the presentation and the tutorial project here:

iPhone Development Tutorial

iPhoneDevelopmentTutorial.zip

If you have any questions, feel free to email me at [email protected] or post a comment. Also, be sure to check out layersforiphone.com.

PackBits algorithm in Objective-C

The PackBits algorithm is one of the TIFF data compression methods, and it’s also used for pixel data in Photoshop PSD and TGA files. It was originally developed for MacPaint, and although it’s still widely used, there isn’t a whole lot of information online about it. I spent some time this weekend writing a category to extend the NSData class and support the packBits algorithm, and I think I’ve finally got it.

PackBits is really dirt simple. If you have a string of hex values like 00 00 00 FF FF FF FF, it replaces series of  3 or more identical bytes with a count, and then the repeated byte. The input above would be 03 00 04 FF. A prefix is also attached to series of different bytes so the decoder knows how many bytes to pass through before looking for another header byte.

The full documentation of PackBits can be found on Wikipedia. My implementation is a modified version of the one available here: http://michael.dipperstein.com/rle/index.html (source link at very bottom of page). That implementation is a modification of the official PackBits algorithm that allows slightly larger runs of data to be encoded in a single header + byte pair. I was interested in the original implementation only (since data written from any customized encoder could not be opened by a standard decoder) so I changed it back to the standard algorithm.

The primary function provided in the PackBitsAdditions category below is:

[objc] – (NSData*)packedBitsForRange:(NSRange)range skip:(int)skip[/objc]

This function returns the packBits representation of the data in “range”, advancing “skip” bytes with each read. For instance, to read and encode every byte in “range”, you would provide skip = 1. To read and encode only every 4th byte, you would pass skip = 4. This may seem like an odd implementation, but it’s very handy when you need to encode the channels of an RGBA image separately (as in PSD format).

The other function in the category is packedBitsDescription. It describes the packed bits and the process that would be followed to decode them. This function could be easily extended to actually decode the data.

If you find this code useful, please leave a comment! I debugged this for quite a while, and I’d be happy to help if you run into any issues with my implementation!

NSDataPackBitsAdditions.h

[objc]

@interface NSData (PackBitsAdditions)

- (NSString*)packedBitsDescription;
- (NSData*)packedBitsForRange:(NSRange)range skip:(int)skip;

@end
[/objc]

NSDataPackBitsAdditions.m

[objc]
@implementation NSData (PackBitsAdditions)

- (NSString*)packedBitsDescription
{
NSMutableString * description = [NSMutableString string];
char * row = (char*)[self bytes];
int pbOffset = 0;
int pbResultBytes = 0;

while (pbOffset < [self length]){
int headerByte = (int)row[pbOffset];
if (headerByte < 0){
int repeatTimes = 1-headerByte;
UInt8 repeatByte = (UInt8)row[pbOffset+1];
[description appendFormat: @"Printing %u %d times. ", repeatByte, repeatTimes];

pbResultBytes += repeatTimes;
pbOffset += 2;
} else if (headerByte >= 0){
[description appendFormat: @"Printing %d literal bytes. ", headerByte + 1];
pbResultBytes += headerByte + 1;
pbOffset += 2 + headerByte;
}
}

[description appendFormat: @"Total: %d bytes decoded.", pbResultBytes];
return description;
}

- (NSData*)packedBitsForRange:(NSRange)range skip:(int)skip
{
char * bytesIn = [self bytes];
int bytesLength = range.location + range.length;
int bytesOffset = range.location;
NSMutableData * dataOut = [NSMutableData data];

BOOL currIsEOF = NO;
unsigned char currChar; /* current character */
unsigned char charBuf[MAX_READ]; /* buffer of already read characters */
int count; /* number of characters in a run */

/* prime the read loop */
currChar = bytesIn[bytesOffset];
bytesOffset = bytesOffset + skip;
count = 0;

/* read input until there’s nothing left */
while (!currIsEOF)
{
charBuf[count] = (unsigned char)currChar;
count++;

if (count >= MIN_RUN){
int i;

/* check for run charBuf[count - 1] .. charBuf[count - MIN_RUN]*/
for (i = 2; i <= MIN_RUN; i++){
if (currChar != charBuf[count - i]){
/* no run */
i = 0;
break;
}
}

if (i != 0){
/* we have a run write out buffer before run*/
int nextChar;

if (count > MIN_RUN){
/* block size – 1 followed by contents */
UInt8 a = count – MIN_RUN – 1;
[dataOut appendBytes:&a length:sizeof(UInt8)];
[dataOut appendBytes:&charBuf length:sizeof(unsigned char) * (count - MIN_RUN)];
}

/* determine run length (MIN_RUN so far) */
count = MIN_RUN;
while (true){
if (bytesOffset < bytesLength){
nextChar = bytesIn[bytesOffset];
bytesOffset += skip;
} else {
currIsEOF = YES;
nextChar = EOF;
}
if (nextChar != currChar) break;

count++;
if (count == MAX_RUN){
/* run is at max length */
break;
}
}

/* write out encoded run length and run symbol */
UInt8 a = ((int)(1 – (int)(count)));
[dataOut appendBytes:&a length:sizeof(UInt8)];
[dataOut appendBytes:&currChar length:sizeof(UInt8)];

if ((!currIsEOF) && (count != MAX_RUN)){
/* make run breaker start of next buffer */
charBuf[0] = nextChar;
count = 1;
} else {
/* file or max run ends in a run */
count = 0;
}
}
}

if (count == MAX_READ){
int i;

/* write out buffer */
UInt8 a = MAX_COPY – 1;
[dataOut appendBytes:&a length:sizeof(UInt8)];
[dataOut appendBytes:&charBuf[0] length:sizeof(unsigned char) * MAX_COPY];

/* start a new buffer */
count = MAX_READ – MAX_COPY;

/* copy excess to front of buffer */
for (i = 0; i < count; i++)
charBuf[i] = charBuf[MAX_COPY + i];
}

if (bytesOffset < bytesLength)
currChar = bytesIn[bytesOffset];
else
currIsEOF = YES;
bytesOffset += skip;
}

/* write out last buffer */
if (0 != count){
if (count <= MAX_COPY){
/* write out entire copy buffer */
UInt8 a = count – 1;
[dataOut appendBytes:&a length:sizeof(UInt8)];
[dataOut appendBytes:&charBuf length:sizeof(unsigned char) * count];
}
else
{
/* we read more than the maximum for a single copy buffer */
UInt8 a = MAX_COPY – 1;
[dataOut appendBytes:&a length:sizeof(UInt8)];
[dataOut appendBytes:&charBuf length:sizeof(unsigned char) * MAX_COPY];

/* write out remainder */
count -= MAX_COPY;
a = count – 1;
[dataOut appendBytes:&a length:sizeof(UInt8)];
[dataOut appendBytes:&charBuf[MAX_COPY] length:sizeof(unsigned char) * count];
}
}

return dataOut;
}

@end
[/objc]

Custom compiler flags in XCode

So I’ve been messing with compiler flags in XCode for the last hour or so, and it turns out I was totally misunderstanding things. If you get info on a project or target in XCode, there’s a “User-Defined” section at the bottom that allows you to create your own flags for use at compile time. However, these flags are not actually passed into GCC! (Mistake 1!) I assumed that adding a key-value pair to the list would pass the flag straight through to GCC, but it appears that they are for use in build scripts, etc…

To pass a custom flag through to GCC so that you can use it in #ifdef and #if macros at compile time, you have to add a User-Defined Setting called “OTHER_CFLAGS”. For my project, I set the value to “-DIS_PHOTO_CHAT=1″. At compile time, the exact text is passed as an argument to GCC. You can set different values in different targets – and I was able to conditionally include some code in a header file using #if (IS_PHOTO_CHAT==1)…

It seems like you can use XCode’s built-in flags like ${TARGET_NAME} and ${PRODUCT_NAME} to insert variables into the value of OTHER_CFLAGS, but if your target name has spaces, I think you’re at a loss. I tried to set -DTARGET_NAME=${TARGET_NAME} for about an hour, but the target name had a space and I can’t get GCC to accept the value (tried quotes… no luck…) I’m no command-line-compiler-whiz, so I’m sure there’s a trick, but Google hasn’t turned anything up.

I’m still surprised OTHER_CFLAGS wasn’t preset to “” in the target build settings. There’s an empty field for “Other Code Signing Flags” (which seems less useful!) Oh well… Guess XCode is in permanent beta anyway?

Creating a UIImage from a CGLayer

CGLayers are great for drawing – especially when things need to be drawn over and over again. Converting a CGLayer to a UIImage is another story, though. NetSketch uses CGLayers for the drawing canvas, but converts them to UIImages when you go to upload your drawing or email it to a friend. The code below shows how it’s done. The CGLayer is drawn into a bitmap CGContext of the same size, and then a CGImage is created around the CGContext. The CGImage can be turned into a UIImage, and you’re done!

Be sure to leave a comment if you find this function useful!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
 
UIImage* UIImageFromLayer(CGLayerRef layer)
{
    // Create the bitmap context
    CGContextRef    bitmapContext = NULL;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;
    CGSize          size = CGLayerGetSize(layer);
 
 
    // Declare the number of bytes per row. Each pixel in the bitmap in this
    // example is represented by 4 bytes; 8 bits each of red, green, blue, and
    // alpha.
    bitmapBytesPerRow   = (size.width * 4);
    bitmapByteCount     = (bitmapBytesPerRow * size.height);
 
 
    // Allocate memory for image data. This is the destination in memory
    // where any drawing to the bitmap context will be rendered.
    bitmapData = malloc( bitmapByteCount );
 
    if (bitmapData == NULL)
    {
        return nil;
    }
 
    // Create the bitmap context. We want pre-multiplied ARGB, 8-bits
    // per component. Regardless of what the source image format is
    // (CMYK, Grayscale, and so on) it will be converted over to the format
    // specified here by CGBitmapContextCreate.
    bitmapContext = CGBitmapContextCreate (bitmapData, size.width, size.height,8,bitmapBytesPerRow,
                                        CGColorSpaceCreateDeviceRGB(),kCGImageAlphaNoneSkipFirst);
 
 
    if (bitmapContext == NULL)
        // error creating context
        return nil;
 
    CGContextScaleCTM(bitmapContext, 1, -1);
    CGContextTranslateCTM(bitmapContext, 0, -size.height);
 
    // Draw the image to the bitmap context. Once we draw, the memory
    // allocated for the context for rendering will then contain the
    // raw image data in the specified color space.
    CGContextDrawLayerAtPoint(bitmapContext, CGPointZero, layer);
    CGImageRef   img = CGBitmapContextCreateImage(bitmapContext);
    UIImage*     ui_img = [UIImage imageWithCGImage: img];
 
    CGImageRelease(img);
    CGContextRelease(bitmapContext);
    free(bitmapData);
 
    return ui_img;
}

A cheap math app – not a good idea?

Earlier this month, I put the finishing touches on Mathomatic and published it to the App Store. Mathomatic is a pretty small app for doing symbolic math. I needed it for a class I took in Signal Processing, and I figured it’d be useful to others as well. It expands and simplifies complex polynomials, takes derivatives and integrals, and a couple other cool things. I built it around the Mathomatic CAS, an open source computer algebra system written in C, and spent most of my time creating a beautiful equation renderer for the iPhone (hopefully to be open sourced soon!)

I decided to sell it for $1.99 because it seemed like a low price would A) increase sales and B) lead to fewer complaints about the limited feature set (After all – how much can you expect for $1.99?). After selling NetSketch for $5.99, I was curious to see how a low priced app would go. I’ve been considering lowering the price on NetSketch, and I thought it’d help determine the optimal price.

Well, it turns out you can expect a lot for $1.99 – at least in the U.S (Interestingly enough, Mathomatic has a much higher rating overseas!). Mathomatic got some bad initial reviews from people looking for more powerful features. The most popular complaints mentioned were:
– Only supports the variables X, Y, and Z
– No support for trigonometric functions
– No in-app help

These are all valid complaints, but they were all things I’d hoped to avoid by pricing the app low. The only other app I’ve heard of that offers similar functionality on the iPhone is SpaceTime, and it’s $19.99. It is, of course, a much richer application with more features and most likely some documentation.

So the real question is – do the people that purchase math apps for the iPhone care how much they cost? Maybe there’s really no space in the market for a “cheap” math app!

Custom UIWebView Navigation Controller

Download Drill Down Example
+ Controller Source
(1.6MB .zip)

The next version of NetSketch will include a community browser, allowing you to view uploaded drawings, watch replays, and leave comments without leaving the app. When I started working on the community interface, I looked to other apps for inspiration. Almost every app I’ve used on the iPhone use a sliding navigation scheme, giving you the feeling that you’re drilling down into content as you use the application. This interface is intuitive in a lot of contexts, and dates back to the original iPod. The Facebook app allows you to browse other people’s Facebook pages and uses a drill down navigation bar. This works well for the social-network space because you can drill down to look at information and then return to the first page quickly.

I decided to use a UINavigationBar and implement a similar drill-down interface for the community part of NetSketch. However, I didn’t want to create custom controllers for each page in the community. I wanted to be able to improve the community without updating the app, and I didn’t want to write a communication layer to download and parse images and custom XML from the server.
Read more

Stopping a Runaway WebView

It turns out, all of the WebViews you create on the iPhone are managed by a central object called WebCore. It seems to be some sort of singleton that takes care of loading content and managing resource loading threads – but it can lead to some interesting problems if you try to rapidly create, display, and release a series of WebViews.

The upcoming version of NetSketch uses WebViews to display community content, but it wraps the web content in an iPhone native navigation bar. That way, there’s a feeling of “drilling down” into pages in the community. (Think: facebook app). It makes it hard to tell the entire thing is  done with WebViews and you get some more user-friendly behavior (like using the top right button in the navigation bar to login/logout). After several iterations, I chose to implement this “drilldown” approach using a custom navigation bar and separate WebViews for each page. A “navigation stack” holds the WebViews of previous pages, and if you drill down too far, they are converted to UIImages and the actual WebViews are released. This behavior helps limit memory consumption, while allowing you to perform common actions quickly (going back and clicking another thumbnail, for example). Keeping images of very old views allows you to rapidly exit the interface without seeing blank pages or waiting for old pages to reload.

Unfortunately, my implementation seems to have run afoul of WebCore. It turns out that if you request a page in a WebView and attempt to release the WebView before it’s done loading, WebCore will attempt to send it delegate messages once it’s been destroyed – and throw exceptions all over the place. My first instinct was to call [webView stopLoading], but that is (apparently) asynchronous and doesn’t actually stop the WebCore from preparing some of the content. If you register an object as a WebView delegate, you’ll notice that you can still recieve webViewDidFinishLoad:(UIWebView *)webView after a stopLoading call.

I messed around with this for a while, and was almost ready to create a “ready-to-release” stack for webViews that were still loading. As a last resort, I tried calling [webView loadRequest: nil], and got some promising results. When you call loadRequest, the WebView  makes an asynchronous call to

[sourcecode language='c']

- (BOOL)webView:(UIWebView *)w shouldStartLoadWithRequest:(NSURLRequest *)r navigationType:(UIWebViewNavigationType)navigationType

[/sourcecode]

When this call returns true, the WebView attempts to load the URL and realizes it is nil. It will almost immediately call – (void)webView:(UIWebView *)w didFailLoadWithError:(NSError *)error, and then it is officially DEAD. You can safetly release the WebView and its delegate without running the risk of further callbacks hitting deallocated objects.

This isn’t a perfect solution (read: it’s a ridiculous hack). It makes stopping and releasing a WebView a multi-step asynchronous process. However, unlike the [webView stopLoading] approach, it results in a consistent series of delegate callbacks that you can observe and also appears to work 100% of the time.

In my implementation, the navigation controller tells a WebView wrapper object to “unlink” the WebView. It detaches itself from everything and calls loadRequest:nil on the WebView. When the didFailLoadWithError: delegate call is received, the WebView is released, the delegate connection is broken and the wrapper is automatically released as well.

So far, so good.

But I still wonder – what exactly does stopLoading do?