<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Codethink &#187; objc</title>
	<atom:link href="https://codethink.no-ip.org/tags/objc/feed" rel="self" type="application/rss+xml" />
	<link>https://codethink.no-ip.org</link>
	<description>A blog about coding, life, and other arbitrary topics</description>
	<lastBuildDate>Sun, 15 Mar 2026 21:30:15 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.29</generator>
	<item>
		<title>Matchbook &#8211; Multi-platform Realtime Gaming</title>
		<link>https://codethink.no-ip.org/archives/1046</link>
		<comments>https://codethink.no-ip.org/archives/1046#comments</comments>
		<pubDate>Sun, 26 Jan 2014 13:56:58 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[objc]]></category>
		<category><![CDATA[open-source]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=1046</guid>
		<description><![CDATA[Have you ever thought that it would be cool if you could build a cross-platform or multi-platform game and connect from one platform to another without having to do all the heavy lifting with respect to matchmaking, communications, and related &#8230; <a href="https://codethink.no-ip.org/archives/1046">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Have you ever thought that it would be cool if you could build a cross-platform or multi-platform game and connect from one platform to another without having to do all the heavy lifting with respect to matchmaking, communications, and related tasks yourself?  Well now you can, thanks to <a href="https://github.com/adam-roth/matchbook" target="_blank">Matchbook</a>.</p>
<div id="attachment_1049" style="width: 650px" class="wp-caption aligncenter"><a href="http://codethink.no-ip.org/wordpress/wp-content/uploads/2014/01/running_small.jpg" rel="lightbox[1046]"><img src="http://codethink.no-ip.org/wordpress/wp-content/uploads/2014/01/running-1200x721.jpg" alt="Matchbook Example &quot;Game&quot;" title="Matchbook Example &quot;Game&quot;" width="640" height="384" class="size-large wp-image-1049" /></a><p class="wp-caption-text">Matchbook Example &quot;Game&quot;, 2x iOS and 2x Android clients</p></div>
<p>Matchbook is a lightweight and platform-agnostic matchmaking solution, intended for use in mobile applications (think games that require near-real-time, relatively-low-latency, persistent communications between two or more client devices).</p>
<p>At its core is a server component, which provides a JSON-based webservice allowing clients to find, create, and join matches. The server also acts as a proxy/relay when necessary, allowing client devices to tunnel through any firewalls that might exist between them.</p>
<p>In addition to the server component, Matchbook includes prebuilt SDK&#8217;s for both Java and Objective-C. These SDK&#8217;s are intended to support the development of native applications that make use of the Matchbook webservice on Android and iOS devices, respectively.</p>
<p>I could go on at length, but it&#8217;s simpler to just link to the project on Github (Matchbook is open-source, and permissively licensed, naturally):</p>
<p><a href="https://github.com/adam-roth/matchbook" target="_blank">https://github.com/adam-roth/matchbook</a></p>
<p>Note that Google is currently building comparable functionality into Google Play, although their realtime communications API is currently only available on Android (iOS support is under development).  </p>
<p>And although Apple already has realtime and turn-based gaming API&#8217;s for iOS, they natually have no intention of inviting Android devices to the party.  Ever.</p>
<p>So let the record show that Matchbook got there first.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/1046/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NSObject+SimpleJson</title>
		<link>https://codethink.no-ip.org/archives/924</link>
		<comments>https://codethink.no-ip.org/archives/924#comments</comments>
		<pubDate>Wed, 08 Jan 2014 07:37:39 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[ios]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=924</guid>
		<description><![CDATA[Certainly the subject of JSON processing on iOS is fairly old-hat at this point. After all, Apple has provided native support for JSON serialization and parsing since the release of iOS 5. So why bring it up now? Personally I&#8217;ve &#8230; <a href="https://codethink.no-ip.org/archives/924">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Certainly the subject of JSON processing on iOS is fairly old-hat at this point.  After all, Apple has provided native support for JSON serialization and parsing since the release of iOS 5.  So why bring it up now?  </p>
<p>Personally I&#8217;ve never been entirely happy with the implementation provided by Apple, and in particular their decision to build their API around <i>NSData</i> instead of <i>NSString</i>.  Granted there&#8217;s probably a reason why Apple chose to go that route, and also a reason why they didn&#8217;t bother to provide convenience methods that allow people to work with whichever type they prefer.  But as far as I&#8217;m concerned, JSON is a textual/non-binary data format, so therefore the natural iOS data structure to use for outputting and inputting JSON data is an <i>NSString</i>.  Using <i>NSData</i> instead is counter-intuitive, and clunky as a result.</p>
<p>So because of that clunkiness, I&#8217;ve stuck with the tried and true <a href="http://superloopy.io/json-framework/?utm_source=ipadsummary&#038;utm_medium=twitter">SBJson</a> library, even though the author of that library himself recommends just using Apple&#8217;s implementation.  This preference is largely based around the very helpful (and also very deprecated) &#8216;<i>NSObject+SBJson</i>&#8216; category that is included in the library.  This category imbues objects with a couple of very convenient methods:</p>
<pre class="brush: cpp; title: ; notranslate">- (NSString*)JSONRepresentation;
- (id)JSONValue;</pre>
<p>These methods can be used to turn an appropriate object (i.e. an <i>NSArray</i> or an <i>NSDictionary</i>) into a JSON string, and to turn a JSON string back into a proper object, respectively.  No parameters, no options, no boxing to or unboxing from <i>NSData</i>; just a simple API that is basically just &#8216;<i>[thing turnIntoJson];</i>&#8216; and &#8216;<i>[json turnBackIntoThing];</i>&#8216;.  It doesn&#8217;t get much more convenient than that.  </p>
<p>And that was all well and good, until I wanted to build a <a href="https://github.com/kstenerud/iOS-Universal-Framework">framework</a> which internally used SBJson, and then use that framework within a project that also needs to make its own use of SBJson.  Linker hell was the result.  And long story short, I decided that it would be faster to build a shim around Apple&#8217;s JSON API to preserve the convenience I&#8217;m after than it would be to appease the linker gods.  </p>
<p>So in case anyone else has been avoiding Apple&#8217;s JSON implementation because it&#8217;s too clunky to work with (or too painful to migrate away from SBJson), here&#8217;s my 5-minute shim:</p>
<p><b>NSObject+SimpleJson.h</b></p>
<pre class="brush: cpp; title: ; notranslate">#import &lt;Foundation/Foundation.h&gt;

@interface NSObject (SimpleJson)

- (NSString *)JSONRepresentation;  //turns an object into a JSON string
- (id)JSONValue;                           //turns a JSON string back into an object

@end</pre>
<p><b>NSObject+SimpleJson.m</b></p>
<pre class="brush: cpp; title: ; notranslate">#import &quot;NSObject+SimpleJson.h&quot;

@implementation NSObject (SimpleJson)

- (NSString*)JSONRepresentation {
    //write ourself to a JSON string; only works if we're a type that 'NSJSONSerialization' supports
    NSError* error = nil;
    NSData* tempData = [NSJSONSerialization dataWithJSONObject:self options:kNilOptions error:&amp;error];
    if (error) {
        return nil;
    }
    
    return [[NSString alloc] initWithData:tempData encoding:NSUTF8StringEncoding];
}


- (id) JSONValue {
    //converts from a string back into a proper object; only works if we're an NSString or NSData instance
    if (! [self isKindOfClass:[NSString class]] &amp;&amp; ! [self isKindOfClass:[NSData class]]) {
        return nil;
    }
    
    NSData* jsonData = nil;
    if ([self isKindOfClass:[NSData class]]) {
        jsonData = (NSData*)self;
    }
    else {
        //we must be an NSString
        jsonData = [((NSString*)self) dataUsingEncoding:NSUTF8StringEncoding];
    }
    
    return [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:nil];
}

@end</pre>
<p>If you have code that uses SBJson&#8217;s &#8216;<i>NSObject+SBJson</i>&#8216; category, the above category should be drop-in compatible.  And just as importantly (in my case) does not invoke linker hell when used as part of an iOS framework.</p>
<p>Note that the above code assumes you are using ARC.  If not, you&#8217;ll want to add an &#8216;<i>autorelease</i>&#8216; call in there.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/924/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Objective-C + Cocoa] Runtime Performance Profiling</title>
		<link>https://codethink.no-ip.org/archives/563</link>
		<comments>https://codethink.no-ip.org/archives/563#comments</comments>
		<pubDate>Fri, 01 Apr 2011 07:25:47 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=563</guid>
		<description><![CDATA[The iPhone SDK and XCode provide some very useful tools for application profiling, particularly with respect to tracking memory consumption and pinpointing memory leaks and other similar issues, but one thing which I have found lacking in the default toolset &#8230; <a href="https://codethink.no-ip.org/archives/563">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>The iPhone SDK and XCode provide some very useful tools for application profiling, particularly with respect to tracking memory consumption and pinpointing memory leaks and other similar issues, but one thing which I have found lacking in the default toolset is the ability to track the execution time of this-or-that specific bit of code, be it a function call, a loop within a function, or some arbitrary series of API calls made in quick succession.  </p>
<p>Typically I would deal with such cases by adding some one-off code around the section that I was interested in profiling to measure and log its execution time.  But this approach quickly becomes unwieldy when there are several different places that you are interested in profiling, and particularly when it comes time to track down and remove all of these bits of code so that they stop spamming the log with timing data that is no longer needed.  </p>
<p>In any case, here is my solution to this minor annoyance, patterned after a similar utility I implemented in ActionScript some time ago:</p>
<pre class="brush: cpp; title: ; notranslate">//PerformanceTimer.h
#import &lt;Foundation/Foundation.h&gt;


@interface PerformanceTimer : NSObject {
    NSMutableArray* startTimes;
    NSMutableArray* names;
}

+ (void) startTimerWithName: (NSString*) name;
+ (clock_t) stopLastTimer;
+ (clock_t) stopTimerWithName: (NSString*) name;

@end


//PerformanceTimer.m
#import &quot;PerformanceTimer.h&quot;

static PerformanceTimer* timerInstance = nil;

@implementation PerformanceTimer

- (id) init {
    self = [super init];
    if (self) {
        startTimes = [[NSMutableArray alloc] initWithCapacity:16];
        names = [[NSMutableArray alloc] initWithCapacity:16];
    }
    
    return self;
}

- (void) dealloc {
    [startTimes release];
    startTimes = nil;
    
    [names release];
    names = nil;
    
    [super dealloc];
}

- (void) startTimer: (NSString*) name {
    @synchronized(startTimes) {
        clock_t start = clock();
        NSNumber* startNum = [NSNumber numberWithUnsignedLong:start];
        [startTimes addObject:startNum];
        [names addObject:name];
    }
}

- (clock_t) stopTimerNamed: (NSString*) name {
    @synchronized(startTimes) {
        int index = 0;
        for (NSString* timerName in names) {
            if ([timerName isEqualToString:name]) {
                break;
            }
            index++;
        }
        if (index &gt;= [names count]) {
            //couldn't find it
            return 0;
        }
        clock_t start = [[startTimes objectAtIndex:index] unsignedLongValue];
        clock_t end = (clock() - start) / (CLOCKS_PER_SEC / 1000.0);
        
        #ifdef DEBUG
        //if debugging, always print, otherwise let the caller decide what to do
        NSLog(@&quot;PerformanceTimer:  Total execution time for task named '%@':  %lu ms&quot;, name, end);
        #endif
        
        [startTimes removeObjectAtIndex:index];
        [names removeObjectAtIndex:index];
        
        return end;
    }
}

- (clock_t) stopTimer {
    @synchronized(startTimes) {
        if ([names count] &lt; 1) {
            //no timer is running
            return 0;
        }
        
        NSString* name = [names objectAtIndex:[names count] - 1];
        return [self stopTimerNamed:name];
    }
}

+ (void) startTimerWithName: (NSString*) name {
    if (! timerInstance) {
        timerInstance = [[PerformanceTimer alloc] init];
    }
    [timerInstance startTimer:name];
}

+ (clock_t) stopLastTimer {
    if (! timerInstance) {
        timerInstance = [[PerformanceTimer alloc] init];
    }
    return [timerInstance stopTimer];
}

+ (clock_t) stopTimerWithName: (NSString*) name {
    if (! timerInstance) {
        timerInstance = [[PerformanceTimer alloc] init];
    }
    return [timerInstance stopTimerNamed:name];
}

@end</pre>
<p>This adds a static utility class that can be used to spawn multiple independent named timers.  It is used like:</p>
<pre class="brush: cpp; title: ; notranslate">[PerformanceTimer startTimer:@&quot;myTimerName&quot;];
//do some things that you want to time
clock_t elapsedTimeMillis = [PerformanceTimer stopTimerWithName: @&quot;myTimerName&quot;];
//print or log the elapsed time</pre>
<p>The default behavior of this class when run in debug mode is to print out the elapsed time automatically when &#8216;stopTimer&#8217; is called, so it&#8217;s not generally necessary to capture or inspect the value returned from &#8216;stopTimer&#8217; unless you are either running in release mode or if you want to do something more involved than simply logging the timing data to the console.</p>
<p>Note that although a &#8216;stopLastTimer&#8217; method is provided for convenience, its use is generally not recommended unless you are absolutely sure that nobody else has started a timer somewhere else in the code.  Otherwise you can end up inadvertently stopping the wrong timer.  Inside of a small, simple, single-threaded application there is little to worry about.  But for any more complex/multi-threaded projects it is much safer to always specify a timer by name.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/563/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[Objective-C + Cocoa] Screen Capture, Multiplexing, and More</title>
		<link>https://codethink.no-ip.org/archives/541</link>
		<comments>https://codethink.no-ip.org/archives/541#comments</comments>
		<pubDate>Mon, 28 Mar 2011 11:45:02 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[cocoa]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=541</guid>
		<description><![CDATA[It&#8217;s been a bit quiet on the coding-front lately, so I thought I&#8217;d share a small handful of various utilities that I&#8217;ve developed over the past few weeks. None of them are particularly revolutionary, but they can certainly prove useful &#8230; <a href="https://codethink.no-ip.org/archives/541">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>It&#8217;s been a bit quiet on the coding-front lately, so I thought I&#8217;d share a small handful of various utilities that I&#8217;ve developed over the past few weeks.  None of them are particularly revolutionary, but they can certainly prove useful in the right situations.  Anyways, in no particular order, I give you:</p>
<p><strong>ScreenCaptureView</strong></p>
<p>This bit of code allows you to easily capture the contents of any arbitrary UIView:</p>
<pre class="brush: cpp; title: ; notranslate">//  ScreenCaptureView.h
#import &lt;UIKit/UIKit.h&gt;

@interface ScreenCaptureView : UIView {
}

@property(retain) UIImage* currentScreen;
@property(assign) float frameRate;

@end


//  ScreenCaptureView.m
#import &quot;ScreenCaptureView.h&quot;
#import &lt;QuartzCore/QuartzCore.h&gt;

@implementation ScreenCaptureView

@synthesize currentScreen, frameRate;

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        self.contentMode = UIViewContentModeRedraw;
        self.frameRate = 20.0f;//20 frames per seconds
    }
    return self;
}

- (void) drawRect:(CGRect)rect {
    CGContextRef context =  UIGraphicsGetCurrentContext();
    [self.layer renderInContext:context];
    CGImageRef cgImage = CGBitmapContextCreateImage(context);
    UIImage* background = [UIImage imageWithCGImage: cgImage];
    CGImageRelease(cgImage);
    self.currentScreen = background;
    
    [self performSelector:@selector(setNeedsDisplay) withObject:nil afterDelay:(1.0 / self.frameRate)];   //redraw at the specified framerate
}

- (void)dealloc {
    [super dealloc];
}
@end</pre>
<p>The &#8216;<em>ScreenCaptureView</em>&#8216; class automatically captures its current contents (including any nested subviews) to a UIImage which it exposes through the &#8216;<em>currentScreen</em>&#8216; property.  You can use this functionality to do things like generate screenshots of your application for use in help/tutorial (or promotional) content, and you can even pass the data as frames to an `<em>AVCaptureSession</em>` to create a live video of your app in action.</p>
<p><strong>Update:</strong>  An enhanced version of this class that includes the ability to record video is <a href="http://codethink.no-ip.org/wordpress/archives/673">now available</a>.</p>
<p><strong>MultiplexingDelegate</strong></p>
<p>For those rare cases when you want multiple delegate objects to be notified of a change/event in some object:</p>
<pre class="brush: cpp; title: ; notranslate">//  MultiplexingDelegate.h
#import &lt;Foundation/Foundation.h&gt;

@interface MultiplexingDelegate : NSObject {
    NSMutableArray* delegates;
}

- (void) addDelegate: (id) theDelegate;
- (void) removeDelegate: (id) theDelegate;
- (void) sendSelectorToDelegates: (SEL)selector withObject: (id)param1 andSecondObject: (id)param2
@end

//  MultiplexingDelegate.m
@implementation MultiplexingDelegate
- (id) init {
    if ((self = [super init])) {
        delegates = [[NSMutableArray alloc] initWithCapacity: 16];
    }
}

- (void) dealloc {
    [delegates release];
    [super dealloc]
}

- (void) addDelegate: (id) theDelegate {
    @synchronized(delegates) {
        if (theDelegate &amp;&amp; ! [delegates containsObject: theDelegate]) {
            [delegates addObject: theDelegate];
        }
    }
}

- (void) removeDelegate: (id) theDelegate {
    @synchronized(delegates) {
        if (theDelegate &amp;&amp; [delegates containsObject: theDelegate]) {
            [delegates removeObject: theDelegate];
        }
    }
}

- (void) sendSelectorToDelegates: (SEL)selector withObject: (id)param1 andSecondObject: (id)param2 {
    @synchronized(delegates) {
        for (id theDelegate in delegates) {
            if (param2) {
                [theDelegate performSelector:selector withObject:param1 withObject:param2];
            }
            else if (param1) {
                [theDelegate performSelector:selector withObject:param1];
            }
            else {
                [theDelegate performSelector:selector];
            }
        }
    }
}
@end</pre>
<p>The &#8216;<em>MultiplexingDelegate</em>` class provides a generic starting point for creating delegates that conform to various protocols and support the multiplexing of events to any number of attached listeners.  To use it you just need to create a new subclass of &#8216;<em>MultiplexingDelegate</em>&#8216; that implements whatever protocol you are interested in.  For instance, here is a partial example of a multiplexing UISearchBarDelegate implementation:</p>
<pre class="brush: cpp; title: ; notranslate">//  MultiplexingSearchBarDelegate.h
#import &lt;UIKit/UIKit.h&gt;
#import &quot;MultiplexingDelegate.h&quot;

@interface MultiplexingSearchBarDelegate : MultiplexingDelegate&lt;UISearchBarDelegate&gt; {
}
@end

//  MultiplexingSearchBarDelegate.m
@implementation MultiplexingSearchBarDelegate
//add UISearchBarDelegate methods here, following a pattern like this:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    [self sendSelectorToDelegates: @selector(searchBar:textDidChange:) withObject: searchBar andSecondObject: searchText];
}

//or alternately/equivalently, a pattern like this:
- (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    @synchronized(delegates) {
        for (id&lt;UISearchBarDelegate&gt; theDelegate in delegates) {
            [theDelegate searchBar:searchBar shouldChangeTextInRange: range replacementText: text];
        }
    }
}
@end</pre>
<p>To use the &#8216;<em>MultiplexingSearchBarDelegate</em>&#8216; class you would create a single instance and add it as the delegate of your UISearchBar.  Then you just register every other object that you want to receive UISearchBar events with the &#8216;<em>MultiplexingSearchBarDelegate</em>&#8216; (by using the &#8216;<em>addDelegate:</em>&#8216; method), and they will all receive event notifications from the UISearchBar.  Simple, but powerful.</p>
<p><strong>NSString+JavaAPI</strong></p>
<p>There&#8217;s no getting around it, the standard NSString API just kind of sucks.  Wouldn&#8217;t it be great if NSString supported an API that was more like what Java provides through its String class?  Well now it can:</p>
<pre class="brush: cpp; title: ; notranslate">//  NSString+JavaAPI.h
#import &lt;Foundation/Foundation.h&gt;

@interface NSString (NSString_JavaAPI)
- (int) compareTo: (NSString*) comp;
- (int) compareToIgnoreCase: (NSString*) comp;
- (bool) contains: (NSString*) substring;
- (bool) endsWith: (NSString*) substring;
- (bool) startsWith: (NSString*) substring;
- (int) indexOf: (NSString*) substring;
- (int) indexOf:(NSString *)substring startingFrom: (int) index;
- (int) lastIndexOf: (NSString*) substring;
- (int) lastIndexOf:(NSString *)substring startingFrom: (int) index;
- (NSString*) substringFromIndex:(int)from toIndex: (int) to;
- (NSString*) trim;
- (NSArray*) split: (NSString*) token;
- (NSString*) replace: (NSString*) target withString: (NSString*) replacement;
- (NSArray*) split: (NSString*) token limit: (int) maxResults;
@end

//  NSString+JavaAPI.m
#import &quot;NSString+JavaAPI.h&quot;

@implementation NSString (NSString_JavaAPI)
- (int) compareTo: (NSString*) comp {
    NSComparisonResult result = [self compare:comp];
    if (result == NSOrderedSame) {
        return 0;
    }
    return result == NSOrderedAscending ? -1 : 1;
}

- (int) compareToIgnoreCase: (NSString*) comp {
    return [[self lowercaseString] compareTo:[comp lowercaseString]];
}

- (bool) contains: (NSString*) substring {
    NSRange range = [self rangeOfString:substring];
    return range.location != NSNotFound;
}

- (bool) endsWith: (NSString*) substring {
    NSRange range = [self rangeOfString:substring];
    return range.location == [self length] - [substring length];
}

- (bool) startsWith: (NSString*) substring {
    NSRange range = [self rangeOfString:substring];
    return range.location == 0;
}

- (int) indexOf: (NSString*) substring {
    NSRange range = [self rangeOfString:substring];
    return range.location == NSNotFound ? -1 : range.location;
}

- (int) indexOf:(NSString *)substring startingFrom: (int) index {
    NSString* test = [self substringFromIndex:index];
    return [test indexOf:substring];
}

- (int) lastIndexOf: (NSString*) substring {
    if (! [self contains:substring]) {
        return -1;
    }
    int matchIndex = 0;
    NSString* test = self;
    while ([test contains:substring]) {
        if (matchIndex &gt; 0) {
            matchIndex += [substring length];
        }
        matchIndex += [test indexOf:substring];
        test = [test substringFromIndex: [test indexOf:substring] + [substring length]];
    }
    
    return matchIndex;
}

- (int) lastIndexOf:(NSString *)substring startingFrom: (int) index {
    NSString* test = [self substringFromIndex:index];
    return [test lastIndexOf:substring];
}

- (NSString*) substringFromIndex:(int)from toIndex: (int) to {
    NSRange range;
    range.location = from;
    range.length = to - from;
    return [self substringWithRange: range];
}

- (NSString*) trim {
    return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}

- (NSArray*) split: (NSString*) token {
    return [self split:token limit:0];
}

- (NSArray*) split: (NSString*) token limit: (int) maxResults {
    NSMutableArray* result = [NSMutableArray arrayWithCapacity: 8];
    NSString* buffer = self;
    while ([buffer contains:token]) {
        if (maxResults &gt; 0 &amp;&amp; [result count] == maxResults - 1) {
            break;
        }
        int matchIndex = [buffer indexOf:token];
        NSString* nextPart = [buffer substringFromIndex:0 toIndex:matchIndex];
        buffer = [buffer substringFromIndex:matchIndex + [token length]];
        if (nextPart) {
            [result addObject:nextPart];
        }
    }
    if ([buffer length] &gt; 0) {
        [result addObject:buffer];
    }
    
    return result;
}

- (NSString*) replace: (NSString*) target withString: (NSString*) replacement {
    return [self stringByReplacingOccurrencesOfString:target withString:replacement];
}
@end</pre>
<p>Note that this isn&#8217;t the complete Java String API (and also that `<em>split()</em>` does not support regular-expressions as it does in Java).  It is just a subset consisting of the most useful Java API functions that do not have convenient analogs in the standard NSString API.  Still, it makes a lot of common string manipulations a lot more straightforward than they otherwise would be.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/541/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>[Cocoa + iPhone] Avoiding &#8216;_handleMemoryWarning:&#8217; Crashes</title>
		<link>https://codethink.no-ip.org/archives/455</link>
		<comments>https://codethink.no-ip.org/archives/455#comments</comments>
		<pubDate>Sat, 05 Mar 2011 02:28:42 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=455</guid>
		<description><![CDATA[Spend enough time developing iPhone applications (particularly if you go to the trouble of collecting crash logs from your apps), and eventually you are bound to come across something like the following: This error occurs most frequently when suspending an &#8230; <a href="https://codethink.no-ip.org/archives/455">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Spend enough time developing iPhone applications (particularly if you go to the trouble of collecting crash logs from your apps), and eventually you are bound to come across something like the following:</p>
<pre class="brush: plain; title: ; notranslate">2011-03-04 14:17:48.872 myApp[15129:307] -[UIImageView _handleMemoryWarning:]: unrecognized selector sent to instance 0x2b2060
[Switching to process 11523 thread 0x0]
2011-03-04 14:17:57.034 myApp[15129:307] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIImageView _handleMemoryWarning:]: unrecognized selector sent to instance 0x2b2060'
*** Call stack at first throw:
(
	0   CoreFoundation                      0x3759dc7b __exceptionPreprocess + 114
	1   libobjc.A.dylib                     0x32d9bee8 objc_exception_throw + 40
	2   CoreFoundation                      0x3759f3e3 -[NSObject(NSObject) doesNotRecognizeSelector:] + 98
	3   CoreFoundation                      0x37544467 ___forwarding___ + 506
	4   CoreFoundation                      0x37544220 _CF_forwarding_prep_0 + 48
	5   Foundation                          0x351663b5 _nsnote_callback + 156
	6   CoreFoundation                      0x37520971 __CFXNotificationPost_old + 396
	7   CoreFoundation                      0x37520611 _CFXNotificationPostNotification + 128
	8   Foundation                          0x351556a3 -[NSNotificationCenter postNotificationName:object:userInfo:] + 70
	9   Foundation                          0x3515edbd -[NSNotificationCenter postNotificationName:object:] + 20
	10  UIKit                               0x35a32354 -[UIApplication _performMemoryWarning] + 68
	11  UIKit                               0x35a33450 -[UIApplication _receivedMemoryNotification] + 184
	12  UIKit                               0x35a2ef24 _memoryStatusChanged + 64
	13  CoreFoundation                      0x37552333 __CFNotificationCenterDarwinCallBack + 26
	14  CoreFoundation                      0x37537e37 __CFMachPortPerform + 218
	15  CoreFoundation                      0x3752f5cb __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 28
	16  CoreFoundation                      0x3752f589 __CFRunLoopDoSource1 + 164
	17  CoreFoundation                      0x37521835 __CFRunLoopRun + 580
	18  CoreFoundation                      0x3752150b CFRunLoopRunSpecific + 226
	19  CoreFoundation                      0x37521419 CFRunLoopRunInMode + 60
	20  GraphicsServices                    0x33e76d24 GSEventRunModal + 196
	21  UIKit                               0x3591d57c -[UIApplication _run] + 588
	22  UIKit                               0x3591a558 UIApplicationMain + 972
	23  myApp                             0x00002649 main + 96
	24  myApp                             0x000025b0 start + 52
)
terminate called after throwing an instance of 'NSException'</pre>
<p>This error occurs most frequently when suspending an app to the background, but it can also happen randomly at other times as well.  Of course, the problem here should be obvious; the crash happens entirely outside of my application code.  After the call to &#8216;<em>main()</em>&#8216; the stack-trace that leads to the crash lies entirely within framework code.  The problem appears to be that some CoreFoundation class is attempting to invoke a &#8216;<em>_handleMemoryWarning:</em>&#8216; selector on objects that do not support it.  </p>
<p>So how to prevent a crash that happens completely outside of your application code?  You might say &#8220;use less memory&#8221;, but that is not a reliable answer here.  The &#8216;<em>_performMemoryWarning</em>&#8216; selector may still be invoked no matter how streamlined your memory usage is.  The answer, or at least the only answer I&#8217;ve found that works reliably, is to use a custom UIApplication subclass and excise the functionality that causes this error, like so:</p>
<pre class="brush: cpp; title: ; notranslate">//
//  SafeUIApplication.h
//  myApp
//
#import &lt;Foundation/Foundation.h&gt;

@interface SafeUIApplication : UIApplication {
}

@end


//
//  SafeUIApplication.m
//  myApp
//
#import &quot;SafeUIApplication.h&quot;

@implementation SafeUIApplication

//these selectors cause crashes in random Foundation classes when the default implementation is called, so instead of crashing our app 
//we ignore these messages, hold on to the memory that has already been allocated to us, and let some other less-clever app crash instead
- (void) _performMemoryWarning {
    NSLog(@&quot;Received a '_performMemoryWarning' call, consider using less memory...&quot;);
    return;
}
- (void) _receivedMemoryNotification {
    NSLog(@&quot;Received a '_receivedMemoryNotification' call, consider using less memory...&quot;);
    return;
}

@end</pre>
<p>Now before the purists and the pedants go jumping down my throat:  Yes, this is a hack.  Yes, it disables built-in memory-management functionality.  Yes, it can mask legitimate problems if your app does in fact have a memory leak (or if it just makes inefficient use of memory).  But having built-in memory-management functionality that crashes the app when called is completely unacceptable in my book, and so disabling it is fair game.  Further, even with this bit of code disabled, the application will still continue to receive low memory warnings (&#8216;<em>didReceiveMemoryWarning</em>&#8216; calls) as normal.  Hanging on to memory that is already allocated to the app cannot cause the app to crash or behave incorrectly, it just means that less memory is available for other apps that are also running.  That seems fair enough to me, at least so long as the default implementation of these methods causes apps to crash.</p>
<p>Anyways, once you&#8217;ve added the SafeUIApplication class to your project, using it is as simple as modifying your application&#8217;s &#8216;main.m&#8217; file like so:</p>
<pre class="brush: cpp; title: ; notranslate">//
//  main.m
//  myApp
//
#import &lt;UIKit/UIKit.h&gt;

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, @&quot;SafeUIApplication&quot;, @&quot;MyAppDelegateClassName&quot;);
    [pool release];
    return retVal;
}</pre>
<p>Just specify the SafeUIApplication classname and your UIApplicationDelegate classname, and you no longer need to worry about obscure &#8216;<em>_handleMemoryWarning:</em>&#8216; crashes.  As noted above, be aware that this will do little to nothing to help applications that have legitimate memory usage issues.  But if you are confident that your application&#8217;s memory usage is correct and you are still experiencing crashes like the one shown above then this little hack will go a very long way towards keeping your application running and stable.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/455/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[Objective-C + Cocoa]  UIScrollView and contentSize</title>
		<link>https://codethink.no-ip.org/archives/357</link>
		<comments>https://codethink.no-ip.org/archives/357#comments</comments>
		<pubDate>Sat, 12 Feb 2011 12:31:17 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=357</guid>
		<description><![CDATA[So here&#8217;s a simple one. For whatever reason, a UIScrollView instance only behaves correctly if you programmatically set its contentSize when you use it. This is fairly silly because in most cases the contentSize is simply the total size of &#8230; <a href="https://codethink.no-ip.org/archives/357">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>So here&#8217;s a simple one.  For whatever reason, a UIScrollView instance only behaves correctly if you programmatically set its contentSize when you use it.  This is fairly silly because in most cases the contentSize is simply the total size of the UIScrollView&#8217;s subview(s).  Why the UIScrollView class doesn&#8217;t provide at least the option of automatically determining its own contentSize based upon its current subviews is beyond me, but here is some simple code to approximate this behavior:</p>
<pre class="brush: cpp; title: ; notranslate">@interface UIScrollView(auto_size)
- (void) adjustHeightForCurrentSubviews: (int) verticalPadding;
- (void) adjustWidthForCurrentSubviews: (int) horizontalPadding;
- (void) adjustWidth: (bool) changeWidth andHeight: (bool) changeHeight withHorizontalPadding: (int) horizontalPadding andVerticalPadding: (int) verticalPadding;
@end

@implementation UIScrollView(auto_size) 
- (void) adjustWidth: (bool) changeWidth andHeight: (bool) changeHeight withHorizontalPadding: (int) horizontalPadding andVerticalPadding: (int) verticalPadding {
    float contentWidth = horizontalPadding;
    float contentHeight = verticalPadding;
    for (UIView* subview in self.subviews) {
        [subview sizeToFit];
        contentWidth += subview.frame.size.width;
        contentHeight += subview.frame.size.height;
    }
    
    contentWidth = changeWidth ? contentWidth : self.superview.frame.size.width;
    contentHeight = changeHeight ? contentHeight : self.superview.frame.size.height;
    
    NSLog(@&quot;Adjusting ScrollView size to %fx%f, verticalPadding=%d, horizontalPadding=%d&quot;, contentWidth, contentHeight, verticalPadding, horizontalPadding);
    self.contentSize = CGSizeMake(contentWidth, contentHeight);
}

- (void) adjustHeightForCurrentSubviews: (int) verticalPadding {
    [self adjustWidth:NO andHeight:YES withHorizontalPadding:0 andVerticalPadding:verticalPadding];
}

- (void) adjustWidthForCurrentSubviews: (int) horizontalPadding {
    [self adjustWidth:YES andHeight:NO withHorizontalPadding:horizontalPadding andVerticalPadding:0];
}
@end</pre>
<p>This code allows a UIScrollView to internally determine its contentSize based upon its current subviews; all you have to do is call one of the three interface methods at an appropriate time (like from within your parent view-controller&#8217;s &#8216;<em>viewDidLoad:</em>&#8216; implementation).  Note that while auto-sizing based upon both width and height is supported, you will only get a correct result for width if all of the UIScrollView&#8217;s subviews span the entire height of the view, and you will only get a correct result for height if all of your subviews span the entire width of the view.  For instance, if you add a thumbnail image to the UIScrollView and then drag a UILabel next to it then both of them will count towards the computed height even though they are logically on the same row.  </p>
<p>You can work around this limitation either by using the &#8216;&#8230;padding&#8217; parameters to adjust the final contentSize, or by adding a UIView that spans the width of the UIScrollView and placing both your thumbnail image and UILabel as subviews of that UIView instead of the UIScrollView.  The latter option of using a nested UIView to contain the content of the row is a better/more maintainable way to build an interface anyways (and also building a UI in Android basically requires you to follow this pattern, so best to get used to it).  But I did try various approaches to solve this problem automatically in the code, such as keeping track min and max x/y coordinates of every subview in the UIScrollView, but this gave inconsistent results between the initial time the view was displayed and subsequent times.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/357/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>[Cocoa + iPhone] UITableViewCell:  It&#8217;s Broken!</title>
		<link>https://codethink.no-ip.org/archives/367</link>
		<comments>https://codethink.no-ip.org/archives/367#comments</comments>
		<pubDate>Thu, 10 Feb 2011 13:27:59 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=367</guid>
		<description><![CDATA[I present for your consideration the following screenshot: It shows a basic table-view, in which each cell has been assigned the same image (using its built-in &#8216;imageView&#8216; property). The source image is 20 pixels square, and the imageView&#8217;s &#8216;contentMode&#8216; property &#8230; <a href="https://codethink.no-ip.org/archives/367">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I present for your consideration the following screenshot:</p>
<p><a href="http://codethink.no-ip.org/wordpress/wp-content/uploads/2011/02/Screen-shot-2011-02-10-at-12.31.37-AM.png" rel="lightbox[367]"><img src="http://codethink.no-ip.org/wordpress/wp-content/uploads/2011/02/Screen-shot-2011-02-10-at-12.31.37-AM.png" alt="UITableViewCell is broken!" title="UITableViewCell is broken!" width="360" height="711" class="aligncenter size-full wp-image-371" /></a></p>
<p>It shows a basic table-view, in which each cell has been assigned the same image (using its built-in &#8216;<em>imageView</em>&#8216; property).  The source image is 20 pixels square, and the imageView&#8217;s &#8216;<em>contentMode</em>&#8216; property has not been changed (not that changing it makes any difference). The image for each row is also being scaled to 50% and rendered at the orientation stated in the cell text.  The code for the table controller is as follows:</p>
<pre class="brush: cpp; title: ; notranslate">#import &quot;UITableViewTestViewController.h&quot;

static NSString* rowNames[8] = {@&quot;UIImageOrientationUp&quot;, @&quot;UIImageOrientationDown&quot;, @&quot;UIImageOrientationLeft&quot;, @&quot;UIImageOrientationRight&quot;, 
                                @&quot;UIImageOrientationUpMirrored&quot;, @&quot;UIImageOrientationDownMirrored&quot;, @&quot;UIImageOrientationLeftMirrored&quot;, 
                                @&quot;UIImageOrientationRightMirrored&quot;};

#define IMAGE_NAME @&quot;testImage.png&quot;

@implementation UITableViewTestViewController

- (void)dealloc {
    [super dealloc];
}

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
}

#pragma mark - View lifecycle
- (int) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 8;  //number of elements in the enumeration
}

- (int) numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString* cellIdentifier = @&quot;TestCell&quot;;
    
    //return a basic cell with the icon in it and some text
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@&quot;StationCell&quot;];
    if (cell == nil) {
        //init cell
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:cellIdentifier] autorelease];
    }
    
    cell.accessoryType = UITableViewCellAccessoryNone;
    cell.textLabel.text = rowNames[indexPath.row];          //enum starts from 0, so indexPath.row matches the orientation that we are going to apply
    cell.textLabel.font = [cell.textLabel.font fontWithSize:12.0];
    cell.textLabel.textColor = [UIColor darkGrayColor];
    cell.imageView.image =  [UIImage imageWithCGImage:[UIImage imageNamed:IMAGE_NAME].CGImage scale:0.5 orientation:indexPath.row];  //the scale operation will be ignored for UIImageOrientationUp; because something is broken
    
    return cell;
}

- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    //it makes no difference if we set the image here
    //cell.imageView.image =  [UIImage imageWithCGImage:[UIImage imageNamed:IMAGE_NAME].CGImage scale:0.5 orientation:indexPath.row];
}
@end</pre>
<p>It&#8217;s not doing anything all that special, but as you can see in the screenshot the image in the first cell is rendered differently than all the others.  More specifically, it is being stretched to the full size of its container so that it just looks kind of sad, and no amount of programmatic scale operations will fix it.  </p>
<p>This can be one of the most maddening aspects about working with table-cells and images.  If you want an image that is slightly smaller than its container in the table-cell, or that is centered away from the top/side, then the only consistent way to do so is to create a custom table-cell.  And while it is not difficult to create a custom table-cell that implements the desired behavior, it needlessly clutters the source-tree with code that replicates functionality that Apple is supposed to be providing out of the box.</p>
<p>The problem, as exposed by this example code, is that when an image is scaled using UIImageOrientationUp (which is what most developers would use, given that they generally store their images in the orientation they want them displayed at) the UITableViewCell completely ignores the scaling operation.  I can only speculate as to the reason for this odd behavior, because at the very least I would expect the output to be the same no matter what UIImageOrientation is used (i.e. I would think that scaling would either consistently not work or consistently work, but this is manifestly not the case).</p>
<p>In any case, this behavior is very clearly a bug, and a particularly inconvenient one at that.  But it does expose a potential workaround that generates less source-clutter than creating a custom table-cell implementation every time you want to have cell images that actually work.  Just store your images upside-down (or preprocess them so that they are upside-down prior to adding to the table) and then invert them back to the proper orientation when you scale them to the size you want for your table.  </p>
<p>It&#8217;s dodgy as all hell to do it that way, but still arguably better than reimplementing functionality that Apple is supposed to be providing out of the box.</p>
<p>Project source code is available here:  <a href="http://codethink.no-ip.org/UITableViewTest.zip">http://codethink.no-ip.org/UITableViewTest.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/367/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Cocoa + iPhone] Unraveling Apple&#8217;s Pagecurl</title>
		<link>https://codethink.no-ip.org/archives/320</link>
		<comments>https://codethink.no-ip.org/archives/320#comments</comments>
		<pubDate>Wed, 09 Feb 2011 13:17:04 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=320</guid>
		<description><![CDATA[First off, I encourage anyone that&#8217;s unfamiliar of this topic to read through this short but very sweet blog post on the subject (and to take a quick look at his sample code). We&#8217;ll be picking up where Steven left &#8230; <a href="https://codethink.no-ip.org/archives/320">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>First off, I encourage anyone that&#8217;s unfamiliar of this topic to read through this <a href="http://blog.steventroughtonsmith.com/2010/02/apples-ibooks-dynamic-page-curl.html" target="_blank">short but very sweet blog post</a> on the subject (and to take a quick look at his sample code).  We&#8217;ll be picking up where Steven left off.</p>
<p>In any case, to summarize the current situation; there exists a private and undocumented API in the iPhone SDK which Apple uses to great effect in their iBook application.  The way to interface with this private API has been discovered and even <a href="http://www.iphonedevwiki.net/index.php?title=CAFilter" target="_blank">fairly well documented</a>.  Using the private API is pretty straightforward but for one small problem:  if you use the private API in your application then Apple will reject your app.  For whatever non-specified reason (probably to keep potential iBook competitors in check), Apple does not want to open up their private API to developers or to play nice with developers who bend the rules and use the private API.  </p>
<p>So our goal is clear.  If Apple isn&#8217;t going to play nice and open the API up to developers, then perhaps we can do some digging to figure out how Apple&#8217;s implementation actually works and create our own implementation that does the same thing.  It&#8217;s a pretty standard exercise in reverse-engineering, really.  The core of the private page-curl API is used like so:</p>
<pre class="brush: cpp; title: ; notranslate">		filter = [[CAFilter filterWithType:kCAFilterPageCurl] retain];
		[filter setDefaults];
		[filter setValue:[NSNumber numberWithFloat:((NSUInteger)fingerDelta)/100.0] forKey:@&quot;inputTime&quot;];
		
		CGFloat _angleRad = angleBetweenCGPoints(currentPos, lastPos);
		CGFloat _angle = _angleRad*180/M_PI ; // I'm far more comfortable with using degrees <img src="https://codethink.no-ip.org/wp-includes/images/smilies/icon_wink.gif" alt=";-)" class="wp-smiley" />
					
		if (_angle &lt; 180 &amp;&amp; _angle &gt; 120) {// here I've limited the results to the right-hand side of the paper. I'm sure there's a better way to do this
			if (fingerVector.y &gt; 0)
				[filter setValue:[NSNumber numberWithFloat:_angleRad] forKey:@&quot;inputAngle&quot;];
			else
				[filter setValue:[NSNumber numberWithFloat:-_angleRad] forKey:@&quot;inputAngle&quot;];

			_internalView.layer.filters = [NSArray arrayWithObject:filter];
		}</pre>
<p>This is an excerpt straight out of Steven Troughton-Smith&#8217;s example.  The example includes additional code related to tracking touch positions and interpolating the angle and distance between them, but this is really the core of the private API right here.  All of the heavy-lifting is handled by the CAFilter class (private), which has a type of &#8216;<em>kCAFilterPageCurl</em>&#8216; (private constant, just the string <em>@&#8221;pageCurl&#8221;</em>, other filter types also exist), and which takes just a small number of input parameters (&#8216;<em>inputTime</em>&#8216; and &#8216;<em>inputAngle</em>&#8216;) and then works its magic behind the scenes.</p>
<p>So given that CAFilter seems to be doing pretty much all the work, it would follow that by constructing our own class that exposes the same interface as CAFilter we can supplant the private-API class with one of our own making (ah, the joys of reflection and weak-typing), thus interfacing with the underlying platform without breaking any of the rules.  But what exactly is a CAFilter?  Is it as onerous as a UIView with its hundreds of methods and properties?  Does it extend another obscure private-API class that will also need to be reverse-engineered?  Well thanks to the &#8216;<em><a href="http://codethink.no-ip.org/wordpress/archives/236">printObject:toDepth:</a></em>&#8216; routine discussed in a previous post we can see that a CAFilter is exactly:</p>
<pre class="brush: cpp; title: ; notranslate">@interface CAFilter : NSObject {
	unsigned int _type;
	NSString* _name;
	unsigned int _flags;
	void* _attr;
	void* _cache;
}

//Constructors
- (id) initWithType:  (NSString*) arg0;
- (id) initWithName:  (NSString*) arg0;

//NSCoding
- (NSObject*) initWithCoder:  (NSCoder*) arg0;
- (void) encodeWithCoder:  (NSCoder*) arg0;

//NSKeyValueCoding
- (void) setValue: (id) arg0 forKey: (NSString*) arg1;
- (id) valueForKey:  (NSString*) arg0;

//NSCopying and NSMutableCopying
- (NSObject*) mutableCopyWithZone:  (NSZone*) arg0;
- (NSObject*) copyWithZone:  (NSZone*) arg0;

//interface methods
- (void) setDefaults;
- (bool) isEnabled;
- (struct UnknownAtomic*) CA_copyRenderValue;

//garbage collection (doesn't need to be declared here)
- (void) dealloc;

//property accessors (don't need to be declared here)
- (bool) enabled;
- (void) setEnabled:  (bool) arg0;
- (bool) cachesInputImage;
- (void) setCachesInputImage:  (bool) arg0;
- (NSString*) name;
- (void) setName:  (NSString*) arg0;
- (NSObject*) type;

//properties
@property(nonatomic, readonly) NSString* type;
@property(nonatomic, retain) NSString* name;
@property(nonatomic) bool enabled;
@property(nonatomic) bool cachesInputImage;

@end</pre>
<p>Nineteen methods and a handful of fields.  Not bad, not bad at all, particularly when many of the methods are simply implementing various publicly-documented protocols such as NSCoding, NSCopying, and NSKeyValueCoding.  As an added bonus, the superclass of CAFilter is NSObject, so the problem has now been reduced to the implementation of a single unknown class (which may still be a Herculean task, but at least now there are clearly-defined boundaries).  </p>
<p>But the above code includes some methods that do not need to be part of the publicly declared interface.  Let&#8217;s clean it up, rename it so that it doesn&#8217;t conflict with the existing private-API class, and add the proper definition of the &#8216;<em>&#8230;Atomic</em>&#8216; struct:</p>
<pre class="brush: cpp; title: ; notranslate">#import &lt;Foundation/Foundation.h&gt;

struct RenderValueResult { 
	int (**x1)(); 
	struct MyAtomic { 
		struct { 
			NSInteger x; 
		} _v; 
	} x2; 
} *_filterResult;

@interface MyCAFilter : NSObject&lt;NSCoding, NSCopying, NSMutableCopying&gt; {
	unsigned int _type;
	NSString* _name;
	unsigned int _flags;
	void* _attr;
	void* _cache;
}

//Constructors
- (id) initWithType:  (NSString*) arg0;
- (id) initWithName:  (NSString*) arg0;

//NSKeyValueCoding
- (void) setValue: (id) arg0 forKey: (NSString*) arg1;
- (id) valueForKey:  (NSString*) arg0;

//interface methods
- (void) setDefaults;
- (bool) isEnabled;
- (struct RenderValueResult*) CA_copyRenderValue;

//properties
@property(nonatomic, readonly) NSString* type;
@property(nonatomic, retain) NSString* name;
@property(nonatomic) bool enabled;
@property(nonatomic) bool cachesInputImage;

@end</pre>
<p>Looking better already.  That &#8216;<em>RenderValueResult</em>&#8216; struct will prove to be a nasty one, but more on that later.</p>
<p>Now that we know the interface, and before we go flying off randomly trying to replicate functionality that we still don&#8217;t fully understand, let&#8217;s take a simpler step.  Let&#8217;s create a simple class that exposes the CAFilter interface, wraps an actual CAFilter instance, and logs each method call, parameters, and result, like so:</p>
<pre class="brush: cpp; title: ; notranslate">//MyCAFilter.h (modified to include 'delegate' field)
#import &lt;Foundation/Foundation.h&gt;

struct RenderValueResult {
    int (**x1)();
    struct MyAtomic {
        struct {
            NSInteger x;
        } _v;
    } x2;
} *_renderValueResult;

@class CAFilter;  //private-API

@interface MyCAFilter : NSObject&lt;NSCoding, NSCopying, NSMutableCopying&gt; {
    unsigned int _type;
    NSString* _name;
    unsigned int _flags;
    void* _attr;
    void* _cache;
    
    CAFilter* delegate;  //private-API
}

//Constructors
- (id) initWithType:  (NSString*) arg0;
- (id) initWithName:  (NSString*) arg0;

//NSKeyValueCoding
- (void) setValue: (id) arg0 forKey: (NSString*) arg1;
- (id) valueForKey:  (NSString*) arg0;

//interface methods
- (void) setDefaults;
- (bool) isEnabled;
- (struct RenderValueResult*) CA_copyRenderValue;

//properties
@property(nonatomic, readonly) NSString* type;
@property(nonatomic, retain) NSString* name;
@property(nonatomic) bool enabled;
@property(nonatomic) bool cachesInputImage;

@end

//MyCAFilter.m
#import &quot;MyCAFilter.h&quot;

@implementation MyCAFilter

@dynamic name, cachesInputImage, type, enabled;

- (id) initWithType: (NSString*) theType {
	NSLog(@&quot;initWithType: type='%@'&quot;, theType);
    if ((self = [super init])) {
        delegate = [[CAFilter alloc] initWithType: theType];    //TODO:  remove delegate
    }
	return self;
}

- (id) initWithName: (NSString*) theName {
	NSLog(@&quot;initWithName: name='%@'&quot;, theName);
    if ((self = [super init])) {
        delegate = [[CAFilter alloc] initWithName: theName];    //TODO:  remove delegate
    }
	return self;
}

- (id) initWithCoder: (NSCoder*) coder {
	NSLog(@&quot;initWithCoder: coder=%@&quot;, coder);
	if ((self = [super init])) {
        delegate = [[CAFilter alloc] initWithCoder: coder];     //TODO:  remove delegate
    }
    return self;
}

- (void) setDefaults {
	NSLog(@&quot;setDefaults&quot;);
	[delegate setDefaults];  //TODO:  remove delegate
}

- (void) encodeWithCoder: (NSCoder*) encoder {
	NSLog(@&quot;encodeWithCoder:  coder=%@&quot;, encoder);
	[delegate encodeWithCoder:encoder];  //TODO:  remove delegate
}

- (id) mutableCopyWithZone: (NSZone*) zone {
    id result = [delegate mutableCopyWithZone:zone];   //TODO:  remove delegate
	NSLog(@&quot;mutableCopyWithZone: zone=%@; result=%@&quot;, zone);
	return result;
}

- (id) copyWithZone: (NSZone*) zone {
    id result = [delegate copyWithZone:zone];  //TODO:  remove delegate
	NSLog(@&quot;copyWithZone:  zone=%@; result=%@&quot;, zone, result);
	return result;
}

- (void) setValue: (id) value forKey: (NSString*) key {
	NSLog(@&quot;setValue:  key=%@, value=%@&quot;, key, value);
	[delegate setValue:value forKey:key];	//TODO:  remove delegate
}

- (id) valueForKey:(id) key {
    id result = [delegate valueForKey:key];  //TODO:  remove delegate
	NSLog(@&quot;valueForKey:  key=%@; result=%@&quot;, key, result);
	return result;
}

- (bool) isEnabled {
    bool result = [delegate isEnabled]; //TODO:  remove delegate
	NSLog(@&quot;isEnabled; result=%d&quot;, result);
	return result; 
}

- (void) dealloc {
	NSLog(@&quot;dealloc&quot;);
	[delegate release];		//TODO:  remove delegate
	[super dealloc];
}

- (bool) enabled {
    bool result = [delegate enabled];		//TODO:  remove delegate
	NSLog(@&quot;enabled; result=%d&quot;, result);
	return result;
}
- (void) setEnabled: (bool) val {
	NSLog(@&quot;setEnabled: value=%d&quot;, val);
	[delegate setEnabled:val];		//TODO:  remove delegate
}

- (void) setCachesInputImage: (bool) val {
	NSLog(@&quot;setCachesInputImage: val=%d&quot;, val);
	[delegate setCachesInputImage:val];		//TODO:  remove delegate
}
- (bool) cachesInputImage {
    bool result = [delegate cachesInputImage];		//TODO:  remove delegate
	NSLog(@&quot;cachesInputImage; result=%d&quot;, result);
	return result;
}

- (id) name {
    id result = [delegate name];		//TODO:  remove delegate
	NSLog(@&quot;name; result=%@&quot;, result);
	return result;
}

- (void) setName: (NSString*) name {
	NSLog(@&quot;setName: name='%@'&quot;, name);
	[delegate setName: name];		//TODO:  remove delegate
}

- (NSString*) type {
    NSString* result = [delegate type];		//TODO:  remove delegate
	NSLog(@&quot;type; result=%@&quot;, result);
	return result;
}

- (struct RenderValueResult*) CA_copyRenderValue {
	struct RenderValueResult* result = [delegate CA_copyRenderValue];	//TODO:  remove delegate
    NSLog(@&quot;CA_copyRenderValue; result=0x%08X, result.x1=0x%08X, result.x2=%d&quot;, result, result-&gt;x1, result-&gt;x2);
	return result;
}

@end</pre>
<p>Using this class is a simple matter of editing &#8216;<em>ReadPdfView.m</em>&#8216; (working with Steven&#8217;s example project) to replace both instances of &#8216;<em>[[CAFilter filterWithType:kCAFilterPageCurl] retain];</em>&#8216; with &#8216;<em>[[MyCAFilter alloc] initWithType: @&#8221;pageCurl&#8221;];</em>&#8216;.  Note that it is also now safe to remove the &#8216;<em>@class CAFilter;</em>&#8216; and &#8216;<em>extern NSString *kCAFilterPageCurl;</em>&#8216; lines from this class.</p>
<p>Now obviously this still won&#8217;t fly with Apple, as it continues to use the private-API CAFilter class.  But consider what we&#8217;ve accomplished; we&#8217;ve now inserted our own custom object into the rendering pipeline, and the core-animation framework is none-the-wiser.  If we can now figure out how to get the same results without internally using the CAFilter instance, we will have cracked the page-curl animation.</p>
<p>Moving along, if we run this code through a complete page-curl animation, we see a very simple pattern emerge:</p>
<pre class="brush: plain; title: ; notranslate">2011-02-09 00:59:11.694 PageCurlDemo[5501:207] initWithType: type='pageCurl'
2011-02-09 00:59:11.707 PageCurlDemo[5501:207] setDefaults
2011-02-09 00:59:11.711 PageCurlDemo[5501:207] setValue:  key=inputTime, value=0
2011-02-09 00:59:11.716 PageCurlDemo[5501:207] setValue:  key=inputAngle, value=-3.141593
2011-02-09 00:59:11.734 PageCurlDemo[5501:207] CA_copyRenderValue; result=0x04AF09E0, result.x1=0x00D96448, result.x2=65538
2011-02-09 00:59:11.767 PageCurlDemo[5501:207] valueForKey:  key=inputTime; result=0
2011-02-09 00:59:11.808 PageCurlDemo[5501:207] dealloc</pre>
<p>This sequence of calls is repeated a number of times as the animation runs.  None of the other methods that exist on the object are called.  Every single one of these calls with the exception of &#8216;<em>CA_copyRenderValue</em>&#8216; originates in the example code; so now our task is constrained to the implementation of a single unknown method.  But what a method it is.  &#8216;<em>CA_copyRenderValue</em>&#8216; returns an instance of a fairly obtuse structure that has the following definition:</p>
<pre class="brush: cpp; title: ; notranslate">struct RenderValueResult { 
	int (**x1)(); 
	struct MyAtomic { 
		struct { 
			NSInteger x; 
		} _v; 
	} x2; 
} *_renderValueResult;</pre>
<p>I&#8217;ve changed the name of the structure and its nested structure to avoid any issues with name collisions, but since the order and type of fields matches the private-API version there should be no issues in terms of compatibility between the different declared versions.  At runtime this structure should be indistinguishable from the private-API version for all practical purposes (barring reflection, which could detect the difference in the naming).</p>
<p>Anyways, this structure contains two fields; &#8216;<em>x1</em>&#8216;, which is a pointer to an array of functions that return integers, and &#8216;<em>x2</em>&#8216;, which is simply an integer.  Interestingly enough, the memory address of the returned data structure never differs by more than 256 bytes between calls, nor do the absolute values of &#8216;<em>x1</em>&#8216; or &#8216;<em>x2</em>&#8216; change.  And here is where things start to get a bit murky.  I&#8217;m going to forget about &#8216;<em>x2</em>&#8216; for a moment, as it is a simple type and its value never seems to vary.  &#8216;<em>x1</em>&#8216; is not so easy.</p>
<p>By inspecting the value of &#8216;<em>x1</em>&#8216;, I&#8217;ve determined that it references no more than 11 distinct functions (the 12th element in the result returned by CAFilter is <em>NULL</em>, and I assume that the <em>NULL</em> indicates the probable end of the meaningful data in the array).  Moreover, the addresses of the functions returned do not appear to vary, even between independent runs of the application.  Which implies to me that perhaps the result being returned is simply referencing some pre-existing object in memory.  </p>
<p>But this is all speculation on my part.  What&#8217;s needed here is more digging, so let&#8217;s create our own callback functions and see what we can discover about the way this data structure is being used by the core-animation framework.  We can do that by adding the following to the MyCAFilter implementation:</p>
<pre class="brush: cpp; title: ; notranslate">int (**originalFuncs)();  //cache for the actual function pointers

//copy/paste this 11 times, incrementing both '0's each time...it's inelegant but it works
int callback0( id firstParam, ... ) {
	int myIndex = 0;
	NSLog(@&quot;callback%d invoked, stack=%@&quot;, myIndex, [NSThread callStackSymbols]);
	
	va_list args;
	va_start(args, firstParam);
	int originalResult = originalFuncs[myIndex](firstParam, args);  //pass any params we recieved on to the original function; not sure if this is the correct way to do this
	
	NSLog(@&quot;callback%d will return result:  %d&quot;, myIndex, originalResult);
	
	return originalResult;
}</pre>
<p>And then by revising &#8216;<em>CA_copyRenderValue</em>&#8216; like so:</p>
<pre class="brush: cpp; title: ; notranslate">void* myCallbacks[11] = {&amp;callback0, &amp;callback1, &amp;callback2, &amp;callback3, &amp;callback4, &amp;callback5, &amp;callback6, &amp;callback7, &amp;callback8, &amp;callback9, &amp;callback10};

- (struct RenderValueResult*) CA_copyRenderValue {
	struct RenderValueResult* result = [delegate CA_copyRenderValue];	//TODO:  remove delegate
	struct RenderValueResult* myResult = malloc(sizeof(struct RenderValueResult));
	myResult-&gt;x2 = result-&gt;x2;  //just copy the integer component of the result; 65538?
	
	//see how many functions there are before we encounter a NULL
	int funcIndex = 0;
	while (result-&gt;x1[funcIndex] != NULL) {
		funcIndex++;
		if (funcIndex &gt;= 11) {
			NSLog(@&quot;CA_copyRenderValue;  NULL sigil not found, assuming max number of functions is 11!&quot;);
			break;
		}
	}
	NSLog(@&quot;CA_copyRenderValue;  found %d functions in delegate's result...&quot;, funcIndex);
	
	myResult-&gt;x1 = malloc(sizeof(int*) * (funcIndex + 1));		//we return this to the CA framework
	originalFuncs = malloc(sizeof(int*) * (funcIndex));			//we keep references to the original functions to use in our callbacks
	for (int index = 0; index &lt; funcIndex ; index++) {
		originalFuncs[index] = result-&gt;x1[index];		//cache the original function pointers
		myResult-&gt;x1[index] = myCallbacks[index];     //put dummy callbacks into the result
	}
	myResult-&gt;x1[funcIndex] = NULL;
	
    NSLog(@&quot;CA_copyRenderValue; result=0x%08X, result.x1=0x%08X, result.x2=%d&quot;, result, result-&gt;x1, result-&gt;x2);
	for (int index = 0; index &lt; funcIndex; index++) {
		NSLog(@&quot;CA_copyRenderValue; result-&gt;x1[%d]=0x%08X&quot;, index, result-&gt;x1[index]);
	}
	return myResult;
}</pre>
<p>Now if we run the application, we get the following output:</p>
<pre class="brush: plain; title: ; notranslate">2011-02-09 23:50:25.508 PageCurlDemo[10453:207] callback3 invoked, stack=(
	0   PageCurlDemo                        0x00006c2b callback3 + 50
	1   QuartzCore                          0x00d63347 CACopyRenderArray + 188
	2   QuartzCore                          0x00cc373e -[CALayer(CALayerPrivate) _copyRenderLayer:layerFlags:commitFlags:] + 1667
	3   QuartzCore                          0x00cc30b4 CALayerCopyRenderLayer + 55
	4   QuartzCore                          0x00cc11d2 _ZN2CA7Context12commit_layerEP8_CALayerjjPv + 122
	5   QuartzCore                          0x00cc10e1 CALayerCommitIfNeeded + 323
	6   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	7   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	8   QuartzCore                          0x00caf7b9 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 1395
	9   QuartzCore                          0x00caf0d0 _ZN2CA11Transaction6commitEv + 292
	10  QuartzCore                          0x00cdf7d5 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 99
	11  CoreFoundation                      0x00ef8fbb __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 27
	12  CoreFoundation                      0x00e8e0e7 __CFRunLoopDoObservers + 295
	13  CoreFoundation                      0x00e56bd7 __CFRunLoopRun + 1575
	14  CoreFoundation                      0x00e56240 CFRunLoopRunSpecific + 208
	15  CoreFoundation                      0x00e56161 CFRunLoopRunInMode + 97
	16  GraphicsServices                    0x0184c268 GSEventRunModal + 217
	17  GraphicsServices                    0x0184c32d GSEventRun + 115
	18  UIKit                               0x002d242e UIApplicationMain + 1160
	19  PageCurlDemo                        0x00002904 main + 102
	20  PageCurlDemo                        0x00002895 start + 53
)
2011-02-09 23:50:25.514 PageCurlDemo[10453:207] callback3 will return result:  9
2011-02-09 23:50:25.519 PageCurlDemo[10453:207] callback3 invoked, stack=(
	0   PageCurlDemo                        0x00006c2b callback3 + 50
	1   QuartzCore                          0x00ce5d12 _ZN2CA6Render7Encoder13encode_objectEPKNS0_6ObjectE + 30
	2   QuartzCore                          0x00ce670d _ZNK2CA6Render5Array6encodeEPNS0_7EncoderE + 113
	3   QuartzCore                          0x00ce5f24 _ZNK2CA6Render5Layer6encodeEPNS0_7EncoderE + 458
	4   QuartzCore                          0x00ce5cdb _ZN2CA6Render17encode_set_objectEPNS0_7EncoderEmjPNS0_6ObjectEj + 91
	5   QuartzCore                          0x00cc1215 _ZN2CA7Context12commit_layerEP8_CALayerjjPv + 189
	6   QuartzCore                          0x00cc10e1 CALayerCommitIfNeeded + 323
	7   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	8   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	9   QuartzCore                          0x00caf7b9 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 1395
	10  QuartzCore                          0x00caf0d0 _ZN2CA11Transaction6commitEv + 292
	11  QuartzCore                          0x00cdf7d5 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 99
	12  CoreFoundation                      0x00ef8fbb __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 27
	13  CoreFoundation                      0x00e8e0e7 __CFRunLoopDoObservers + 295
	14  CoreFoundation                      0x00e56bd7 __CFRunLoopRun + 1575
	15  CoreFoundation                      0x00e56240 CFRunLoopRunSpecific + 208
	16  CoreFoundation                      0x00e56161 CFRunLoopRunInMode + 97
	17  GraphicsServices                    0x0184c268 GSEventRunModal + 217
	18  GraphicsServices                    0x0184c32d GSEventRun + 115
	19  UIKit                               0x002d242e UIApplicationMain + 1160
	20  PageCurlDemo                        0x00002904 main + 102
	21  PageCurlDemo                        0x00002895 start + 53
)
2011-02-09 23:50:25.527 PageCurlDemo[10453:207] callback3 will return result:  9
2011-02-09 23:50:25.536 PageCurlDemo[10453:207] callback3 invoked, stack=(
	0   PageCurlDemo                        0x00006c2b callback3 + 50
	1   QuartzCore                          0x00ce5d34 _ZN2CA6Render7Encoder13encode_objectEPKNS0_6ObjectE + 64
	2   QuartzCore                          0x00ce670d _ZNK2CA6Render5Array6encodeEPNS0_7EncoderE + 113
	3   QuartzCore                          0x00ce5f24 _ZNK2CA6Render5Layer6encodeEPNS0_7EncoderE + 458
	4   QuartzCore                          0x00ce5cdb _ZN2CA6Render17encode_set_objectEPNS0_7EncoderEmjPNS0_6ObjectEj + 91
	5   QuartzCore                          0x00cc1215 _ZN2CA7Context12commit_layerEP8_CALayerjjPv + 189
	6   QuartzCore                          0x00cc10e1 CALayerCommitIfNeeded + 323
	7   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	8   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	9   QuartzCore                          0x00caf7b9 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 1395
	10  QuartzCore                          0x00caf0d0 _ZN2CA11Transaction6commitEv + 292
	11  QuartzCore                          0x00cdf7d5 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 99
	12  CoreFoundation                      0x00ef8fbb __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 27
	13  CoreFoundation                      0x00e8e0e7 __CFRunLoopDoObservers + 295
	14  CoreFoundation                      0x00e56bd7 __CFRunLoopRun + 1575
	15  CoreFoundation                      0x00e56240 CFRunLoopRunSpecific + 208
	16  CoreFoundation                      0x00e56161 CFRunLoopRunInMode + 97
	17  GraphicsServices                    0x0184c268 GSEventRunModal + 217
	18  GraphicsServices                    0x0184c32d GSEventRun + 115
	19  UIKit                               0x002d242e UIApplicationMain + 1160
	20  PageCurlDemo                        0x00002904 main + 102
	21  PageCurlDemo                        0x00002895 start + 53
)
2011-02-09 23:50:25.566 PageCurlDemo[10453:207] callback3 will return result:  9
2011-02-09 23:50:25.578 PageCurlDemo[10453:207] callback4 invoked, stack=(
	0   PageCurlDemo                        0x00006cca callback4 + 50
	1   QuartzCore                          0x00ce670d _ZNK2CA6Render5Array6encodeEPNS0_7EncoderE + 113
	2   QuartzCore                          0x00ce5f24 _ZNK2CA6Render5Layer6encodeEPNS0_7EncoderE + 458
	3   QuartzCore                          0x00ce5cdb _ZN2CA6Render17encode_set_objectEPNS0_7EncoderEmjPNS0_6ObjectEj + 91
	4   QuartzCore                          0x00cc1215 _ZN2CA7Context12commit_layerEP8_CALayerjjPv + 189
	5   QuartzCore                          0x00cc10e1 CALayerCommitIfNeeded + 323
	6   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	7   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	8   QuartzCore                          0x00caf7b9 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 1395
	9   QuartzCore                          0x00caf0d0 _ZN2CA11Transaction6commitEv + 292
	10  QuartzCore                          0x00cdf7d5 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 99
	11  CoreFoundation                      0x00ef8fbb __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 27
	12  CoreFoundation                      0x00e8e0e7 __CFRunLoopDoObservers + 295
	13  CoreFoundation                      0x00e56bd7 __CFRunLoopRun + 1575
	14  CoreFoundation                      0x00e56240 CFRunLoopRunSpecific + 208
	15  CoreFoundation                      0x00e56161 CFRunLoopRunInMode + 97
	16  GraphicsServices                    0x0184c268 GSEventRunModal + 217
	17  GraphicsServices                    0x0184c32d GSEventRun + 115
	18  UIKit                               0x002d242e UIApplicationMain + 1160
	19  PageCurlDemo                        0x00002904 main + 102
	20  PageCurlDemo                        0x00002895 start + 53
)</pre>
<p>Followed by a crash.  Something causes the attempt to invoke the fourth callback function to die; probably related to the questionable way that I&#8217;m passing arguments to it.  Not knowing what the proper signature for the callback functions is, I&#8217;ve made them all accept a variable number of &#8216;id&#8217; parameters, which should cover most cases.  However the best way to pass these arguments on to the original implementation is not clear.  </p>
<p>For what it&#8217;s worth, I tried a number of alternate ways to invoke this function, all of which resulted in a crash.  Skipping the invocation and just returning a hard-coded value from my callback prevented the crash, but didn&#8217;t result in any more callbacks being invoked.  Presumably core-animation noticed that my hard-coded return value didn&#8217;t match what it was expecting, and decided to abort the rest of its rendering transaction.  </p>
<p>And unfortunately, here is where I need to leave this interesting little diversion for now, unless/until I can figure out a way to move it forward.  If you have any suggestions please don&#8217;t hesitate to let me know.  I feel like I&#8217;m getting close to the answer here, but it&#8217;s still quite a ways away.</p>
<p><strong>Update</strong></p>
<p>If anyone is interested, you can download a complete <a href="http://codethink.no-ip.org/PageCurlDemo_modified.zip">XCode project</a> containing the latest revision of my code.  If you decide to take a crack at solving this problem, I wish you luck, and please do consider reporting back with your results.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/320/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>[Objective-C + Cocoa] NSAutoreleasePool and Threads</title>
		<link>https://codethink.no-ip.org/archives/289</link>
		<comments>https://codethink.no-ip.org/archives/289#comments</comments>
		<pubDate>Fri, 04 Feb 2011 11:58:09 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=289</guid>
		<description><![CDATA[If you have a multithreaded iPhone/iPad/Cocoa application, you are probably aware that for each thread you create you need to set up an auto-release pool for that thread. If you don&#8217;t do this then you&#8217;ll get some nice messages in &#8230; <a href="https://codethink.no-ip.org/archives/289">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>If you have a multithreaded iPhone/iPad/Cocoa application, you are probably aware that for each thread you create you need to set up an auto-release pool for that thread.  If you don&#8217;t do this then you&#8217;ll get some nice messages in your debugger log informing you that your app is leaking memory (for shame!).  Personally I think that any boilerplate code that must be added to each thread should be handled automatically by the SDK/runtime environment, but that&#8217;s completely beside the point here.  The point here is that the standard example given for this boilerplate code is generally something along the lines of:</p>
<pre class="brush: cpp; title: ; notranslate">- (void) myThreadEntryPoint {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  //set up a pool
	// [do work here]
	[pool drain];
}</pre>
<p>And this is all well and good for simple use-cases, but often a developer wants to have a thread that runs forever (or for the lifetime of the application), in which case the &#8216;<em>[do work here]</em>&#8216; section might look like:</p>
<pre class="brush: cpp; title: ; notranslate">while (! [self shouldTerminate]) {
	//[do some stuff]
	[NSThread sleepForTimeInterval:10.0s];  //sleep for a bit
}</pre>
<p>If we insert this code into the standard boilerplate example, we get the following:</p>
<pre class="brush: cpp; title: ; notranslate">- (void) myThreadEntryPoint {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  //set up a pool
	while (! [self shouldTerminate]) {
		//[do some stuff]
		[NSThread sleepForTimeInterval:10.0s];  //sleep for a bit
	}
	[pool drain];
}</pre>
<p>And now we have a problem, one that&#8217;s particularly easy for new developers to create.  Technically this code is following the standard example, but it is also creating a slow memory leak, assuming that any amount of non-trivial work is being performed in the &#8216;<em>[do some stuff]</em>&#8216; section.  The problem is that the auto-release pool is never drained until the thread is ready to terminate, meaning that all the objects that are in the pool do not get released.  They simply accumulate in memory.  If you write code like what&#8217;s shown above, a crash is inevitable; it&#8217;s only a question of when.</p>
<p>In an environment as memory-constrained as an iPhone, anything accumulating in memory is a Very Bad Thing&trade;.  Doubly so in this case because the issue will not be detected in debugging tools like Leaks or Allocations.  You will not get any console messages nagging you about memory leaks.  You have an auto-release pool in place, after all, and you&#8217;re releasing it properly, so how is the compiler or any other tool to know that there&#8217;s an issue (in fact, in order to detect that there is an issue in the above code the compiler would have to be able to solve the <a href="http://en.wikipedia.org/wiki/Halting_problem" target="_blank">halting problem</a>)?  </p>
<p>If you code like this, your application will just slowly consume more and more memory until it eventually crashes.  And you can&#8217;t even count on getting a reliable stack-trace when it does crash, because the allocation that finally brings the thing crashing down might be nowhere near the code associated with the actual leak.  </p>
<p>Luckily, this error is simple to avoid.  Just change the code so that it&#8217;s like this:</p>
<pre class="brush: cpp; title: ; notranslate">- (void)myThreadEntryPoint {	
	while (![self shouldTerminate]) {
		NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
		
		//[do work here]

		[pool drain];  
		[NSThread sleepForTimeInterval:10.0s];  //sleep for a bit
	}
}</pre>
<p>And problem solved.  The auto-release pool is released and reset on each iteration of the loop, as soon as we are done doing our actual work.  Objects are released, memory is freed, everyone is happy, and on the next loop iteration the process starts over again.  It&#8217;s a very simple fix, but the issue that it addresses is easy to overlook, and difficult to track down once overlooked.</p>
<p>Note that this is mentioned in Apple&#8217;s official documentation on the subject, which states:</p>
<pre class="brush: plain; title: ; notranslate">If your application or thread is long-lived and potentially generates a lot of 
autoreleased objects, you should periodically drain and create autorelease pools 
(like the Application Kit does on the main thread); otherwise, autoreleased 
objects accumulate and your memory footprint grows. If, however, your detached 
thread does not make Cocoa calls, you do not need to create an autorelease pool.</pre>
<p>So if you missed it in the official documentation before, now you know; and hopefully you also know why it&#8217;s important to pay attention to this little piece of advice.  If you don&#8217;t want your application to crash and die randomly, that is.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/289/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[Objective-C + Cocoa] Object Inspection</title>
		<link>https://codethink.no-ip.org/archives/236</link>
		<comments>https://codethink.no-ip.org/archives/236#comments</comments>
		<pubDate>Tue, 01 Feb 2011 10:57:03 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=236</guid>
		<description><![CDATA[I&#8217;m a big fan of reflection. Always have been since I was first exposed to it in Java. For those not familiar with the concept, reflection (or introspection as it is alternately called) allows one to inspect and/or access the &#8230; <a href="https://codethink.no-ip.org/archives/236">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I&#8217;m a big fan of <a href="http://en.wikipedia.org/wiki/Reflection_(computer_science)" target="_blank">reflection</a>.  Always have been since I was first exposed to it in Java.  For those not familiar with the concept, reflection (or introspection as it is alternately called) allows one to inspect and/or access the properties and methods of an object instance at runtime, without needing any specific details about its declared type or fields.  Though it may seem like a fairly minor feature, reflection is used to great effect in the Java world by the likes of <a href="http://www.springsource.org/" target="_blank">Spring</a> and <a href="http://easymock.org/" target="_blank">EasyMock</a>, to name just a few.  </p>
<p>So it&#8217;s a bit puzzling to me, then, that reflection seems to have been long forgotten in the realm of Objective-C.  Apple&#8217;s <a href="http://developer.apple.com/library/mac/#documentation/cocoa/reference/objcruntimeref/Reference/reference.html" target="_blank">official documentation on this topic</a> even mildly discourages its use (&#8220;You typically do not need to use the Objective-C runtime library directly when programming in Objective-C&#8221;).  Granted, the <em>performSelector:</em> method sees fairly frequent use in many Cocoa applications, but this is a minor concession in a language where virtually every method-call resolves to a table lookup to find the implementation of the method being called (and you can even swap method implementations around at runtime by mucking with the lookup table).  </p>
<p>So as a demonstration of some of the neat things that can be done using reflection in Objective-C, I&#8217;ve put together some code that will &#8220;deconstruct&#8221; an arbitrary object.  This code will:</p>
<ul>
<li>Print the signature of any methods that exist on an object.</li>
<li>Print the name and type of any properties declared on the object</li>
<li>Print the name and type of any instance-level fields declared as members of the object.</li>
<li>Optionally recurse through any non-primitive non-nil field/property types.</li>
<li>Optionally recurse through the object&#8217;s superclasses until the root class (<em>NSObject</em>, typically) is reached.</li>
<li>Attempt to track and return the real amount of memory allocated to the object (not fully accurate).</li>
</ul>
<p>The code is packaged as a category on <em>NSObject</em>, meaning that if you include it in your project you can simply call &#8216;<em>[obj printObject:obj toDepth:0]</em>&#8216; in order to print the details of any object you are interested in.  Anyways, here is the code that works all the magic:</p>
<pre class="brush: cpp; title: ; notranslate">#import &lt;objc/objc-class.h&gt;
#import &lt;malloc/malloc.h&gt;

@implementation NSObject(object_print)

- (NSString*) appendTo: (NSString*) base with: (NSString*) rest {
	return [NSString stringWithFormat:@&quot;%@%@&quot;, base, rest];
}

- (int) printObjectInternal:(id)anObject printState: (NSMutableArray*)state friendlyName: (NSString*) objName withIndent: (NSString*)indent fromDepth: (int)currentDepth toDepth: (int)maxDepth {
	if (anObject == nil || anObject == NULL || currentDepth &gt; maxDepth) {
		//nothing to do
		return 0;
	}
	
	[state addObject:anObject];
	
	//process properties for the class and its superclass(es)
	int totalSize = 0;
	int mySuperclassDepth = currentDepth;
	Class processingClass = [anObject class];
	while (processingClass != nil &amp;&amp; processingClass != [NSObject class] &amp;&amp; mySuperclassDepth &lt;= maxDepth) {
		unsigned int numFields = 0;
		
		//methods
		Method* methods = class_copyMethodList(processingClass, &amp;numFields);
		NSLog(@&quot;[%@] - %@  Printing object:  type=%@ : %@ ...&quot;, objName, indent, processingClass, class_getSuperclass(processingClass));
		NSLog(@&quot;[%@] - %@  Printing object methods:  type=%@, numMethods=%d&quot;, objName, indent, processingClass, numFields);
		for (int index = 0; index &lt; numFields; index++) {
			unsigned int numArgs = method_getNumberOfArguments(methods[index]);
			const char* name = sel_getName(method_getName(methods[index]));
			NSString* argString = @&quot;&quot;;
			char* copyReturnType = method_copyReturnType(methods[index]);
			for (int argIndex = 0; argIndex &lt; numArgs; argIndex++) {
				char* argType = method_copyArgumentType(methods[index], argIndex);
				if (argIndex &gt; 2) {
					argString = [argString stringByAppendingFormat:@&quot; argName%d: (%@) arg%d&quot;, argIndex - 2, [self codeToReadableType: argType], argIndex - 2]; 
				}
				else if (argIndex &gt; 1) {
					argString = [argString stringByAppendingFormat:@&quot; (%@) arg%d&quot;, [self codeToReadableType: argType], argIndex - 2];
				}
				free(argType);
			}
			
			if (numArgs &lt;= 2) {
				NSLog(@&quot;[%@] - %@ (%@)  - (%@) %s;&quot;, objName, indent, processingClass, [self codeToReadableType: copyReturnType], name);
			}
			else {
				NSLog(@&quot;[%@] - %@ (%@)  - (%@) %s %@;&quot;, objName, indent, processingClass, [self codeToReadableType: copyReturnType], name, argString);
			}
			free(copyReturnType);
		}
		
		//properties (i.e. things declared with '@property')
		objc_property_t* props = class_copyPropertyList(processingClass, &amp;numFields);
		NSLog(@&quot;[%@] - %@  Printing object properties:  type=%@, numFields=%d&quot;, objName, indent, processingClass, numFields);
		for (int index = 0; index &lt; numFields; index++) {
			objc_property_t prop = props[index];
			const char* fieldName = property_getName(prop);
			const char* fieldType = property_getAttributes(prop);
			NSLog(@&quot;[%@] - %@ (%@) @property %@ %s;&quot;, objName, indent, processingClass, [self codeToReadableType: fieldType], fieldName);
			
			@try {
				id fieldValue = [anObject valueForKey:[NSString stringWithFormat:@&quot;%s&quot;, fieldName]];
				totalSize += malloc_size(fieldValue);
				NSString* typeString = [NSString stringWithFormat:@&quot;%s&quot;, fieldType];
				NSRange range = [typeString rangeOfString:@&quot;T@\&quot;&quot;];
				if (range.location == 0 &amp;&amp; fieldValue &amp;&amp; ! [state containsObject:fieldValue]) {
					//the field is an object-type, so print its size as well
					NSLog(@&quot;[%@] - %@ (%@)\t  Expanding property [%s]:&quot;, objName, indent, processingClass, fieldName);
					totalSize += [self printObjectInternal: fieldValue printState: state friendlyName: objName withIndent: [NSString stringWithFormat:@&quot;%@\t&quot;, indent] fromDepth: mySuperclassDepth + 1 toDepth: maxDepth];
				}
			}
			@catch (id ignored) {
				//couldn't get it with objectForKey, so try an alternate way
				void* fieldValue = NULL;
				object_getInstanceVariable(anObject, fieldName, &amp;fieldValue);
				if (fieldValue != NULL &amp;&amp; fieldValue != nil) {
					totalSize += malloc_size(fieldValue);
				}
			}
		}
		
		//ivars (i.e. declared instance members)
		Ivar* ivars = class_copyIvarList(processingClass, &amp;numFields);
		NSLog(@&quot;[%@] - %@ (%@) Printing object ivars:  type=%@, numFields=%d&quot;, objName, indent, processingClass, processingClass, numFields);
		for (int index = 0; index &lt; numFields; index++) {
			Ivar ivar = ivars[index];
			id fieldValue = object_getIvar(anObject, ivar);
			
			const char* fieldName = ivar_getName(ivar);
			const char* fieldType = ivar_getTypeEncoding(ivar);
			
			NSLog(@&quot;[%@] - %@ (%@) %@ %s;&quot;, objName, indent, processingClass, [self codeToReadableType: fieldType], fieldName);
			int mSize = malloc_size(fieldValue);
			totalSize += mSize;
			
			@try {
				NSString* typeString = [NSString stringWithFormat:@&quot;%s&quot;, fieldType];
				NSRange range = [typeString rangeOfString:@&quot;@&quot;];
				if (range.location == 0 &amp;&amp; (! [state containsObject:fieldValue]) &amp;&amp; mSize &gt; 0) {
					//the field is an object-type, so print its size as well
					NSLog(@&quot;[%@] - %@ (%@)\t  Expanding ivar [%s]:&quot;, objName, indent, processingClass, fieldName);
					totalSize += [self printObjectInternal: fieldValue printState: state friendlyName: objName withIndent: [NSString stringWithFormat:@&quot;%@\t&quot;, indent] fromDepth: mySuperclassDepth + 1 toDepth: maxDepth];
					
					//see if it's a countable type, just for fun
					if ([fieldValue respondsToSelector:@selector(count)]) {
						//if we can count it, print the count
						NSLog(@&quot;[%@] - %@ (%@)\t\t  Container Count:  name=%s, type=%s, count=%d&quot;, objName, indent, processingClass, fieldName, fieldType, [fieldValue count]);
					}
				}
			}
			@catch (id ignored) {
				//couldn't print it
			}
		}
		
		//process indexed ivars (extra bytes allocated at end of object; no name available, just size)
		void* extraBytes = object_getIndexedIvars(anObject);
		NSLog(@&quot;[%@] - %@ (%@) Printing object indexedIvars:  type=%@, extraBytes=%d&quot;, objName, indent, processingClass, processingClass, malloc_size(extraBytes));
		
		//process superclass
		NSLog(@&quot;[%@] - %@ (%@) Superclass of %@ is %@&quot;, objName, indent, processingClass, processingClass, class_getSuperclass(processingClass));
		processingClass = class_getSuperclass(processingClass);
		mySuperclassDepth++;
	}
	
	return totalSize;
}

- (int) printObject: (id)anObject toDepth: (int) maxDepth {
	if (! anObject) {
		anObject = self;
	}
	if (maxDepth &lt; 0) {
		maxDepth = 0;
	}
	NSMutableArray* state = [[NSMutableArray alloc] initWithCapacity: 1024];
	int result = [self printObjectInternal:anObject printState: state friendlyName: [[anObject class] description] withIndent: @&quot;&quot; fromDepth: 0 toDepth: maxDepth];
	[state release];
	
	return result;
}

@end</pre>
<p>One minor omission from the above code is the <em>codeToReadableType:</em> function.  This method simply takes an Objective-C type code (things like &#8220;^^f&#8221; and &#8220;C&#8221; and &#8220;:&#8221;) and parses it back into a human-readable format.  It&#8217;s rather verbose for what it does, so it&#8217;s available at the end of this post.</p>
<p>Anyways, this code imbues any type derived from <em>NSObject</em> with a &#8216;<em>printObject:toDepth:</em>&#8216; method which does pretty much what its name implies.  For a given object, it will print information about its methods, properties, and fields, and if you specify a depth greater than 0 it will also recurse through any non-primitive property or field and also the object&#8217;s superclass(es) to the specified depth limit.  Want to know all 327 methods that exist on a <em>UIView</em> instance, including the ones that Apple doesn&#8217;t tell you about?  Then invoke this method on a <em>UIView</em> instance, or on an instance of anything that extends <em>UIView</em> using a &#8216;<em>toDepth:</em>&#8216; of 1 or greater.</p>
<p>Also note that this method is designed to handle circular references in the object hierarchy and avoid getting trapped in a cycle; if you paid close attention to the code you will have noticed the &#8216;<em>state</em>&#8216; array, which keeps track of every object instance that has been encountered in the hierarchy.  Before recursing through a new object instance the method first checks this array to make sure that instance hasn&#8217;t already been encountered, and avoids recursing through the object if it has already been seen.  So you don&#8217;t have to worry about circular references killing the &#8216;<em>printObject:toDepth:</em>&#8216; routine.</p>
<p>All-told, this code can be quite fun to play with if you&#8217;re curious about your Objective-C runtime environment.  It lets you see in a human-readable way what the object hierarchy looks like in memory.  Note that while this code also attempts to keep track of the number of bytes allocated by each object it traverses, it does not do a complete job of it, and the returned value shouldn&#8217;t be assumed to be an accurate representation of the size of the object instance.  It may work for simple types, but you certainly shouldn&#8217;t rely on it for anything significant.  </p>
<p>Lastly, here is the <em>codeToReadableType:</em> implementation.  It could almost certainly be more compactly written using regular expressions and pattern matching, but this will get the job done.  Just include it as part of the category, and you&#8217;ll be all set.</p>
<pre class="brush: cpp; title: ; notranslate">- (NSString*) codeToReadableType: (const char*) code {
	NSString* codeString = [NSString stringWithFormat:@&quot;%s&quot;, code];
	NSString* result = [NSString stringWithString:@&quot;&quot;];
	
	bool array = NO;
	NSString* arrayString;
	//note:  we parse our type from left to right, but build our result string from right to left
	for (int index = 0; index &lt; [codeString length]; index++) {
		char nextChar = [codeString characterAtIndex:index];
		switch (nextChar) {
			case 'T':
				//a placeholder code, the actual type will be specified by the next character
				break;
			case ',':
				//used in conjunction with 'T', indicates the end of the data that we care about 
				//we could further process the character(s) after the comma to work out things like 'nonatomic', 'retain', etc., but let's not
				index = [codeString length];
				break;
			case 'i':
				//int or id
				if (index + 1 &lt; [codeString length] &amp;&amp; [codeString characterAtIndex:index + 1] == 'd') {
					//id
					result = [self appendTo: (array ? @&quot;id[&quot; : @&quot;id&quot;) with: result];
					index++;
				}
				else {
					//int
					result = [self appendTo: (array ? @&quot;int[&quot; : @&quot;int&quot;) with: result];
				}
				break;
			case 'I':
				//unsigned int
				result = [self appendTo: (array ? @&quot;unsigned int[&quot; : @&quot;unsigned int&quot;) with: result];
				break;
			case 's':
				//short
				result = [self appendTo: (array ? @&quot;short[&quot; : @&quot;short&quot;) with: result];
				break;
			case 'S':
				//unsigned short
				result = [self appendTo: (array ? @&quot;unsigned short[&quot; : @&quot;unsigned short&quot;) with: result];
				break;
			case 'l':
				//long
				result = [self appendTo: (array ? @&quot;long[&quot; : @&quot;long&quot;) with: result];
				break;
			case 'L':
				//unsigned long
				result = [self appendTo: (array ? @&quot;unsigned long[&quot; : @&quot;unsigned long&quot;) with: result];
				break;
			case 'q':
				//long long
				result = [self appendTo: (array ? @&quot;long long[&quot; : @&quot;long long&quot;) with: result];
				break;
			case 'Q':
				//unsigned long long
				result = [self appendTo: (array ? @&quot;unsigned long long[&quot; : @&quot;unsigned long long&quot;) with: result];
				break;
			case 'f':
				//float
				result = [self appendTo: (array ? @&quot;float[&quot; : @&quot;float&quot;) with: result];
				break;
			case 'd':
				//double
				result = [self appendTo: (array ? @&quot;double[&quot; : @&quot;double&quot;) with: result];
				break;
			case 'B':
				//bool
				result = [self appendTo: (array ? @&quot;bool[&quot; : @&quot;bool&quot;) with: result];
				break;
			case 'b':
				//char and BOOL; is stored as &quot;bool&quot;, so need to ignore the next 3 chars
				result = [self appendTo: (array ? @&quot;BOOL[&quot; : @&quot;BOOL&quot;) with: result];
				index += 3;
				break;
			case 'c':
				//char?
				result = [self appendTo: (array ? @&quot;char[&quot; : @&quot;char&quot;) with: result];
				break;
			case 'C':
				//unsigned char
				result = [self appendTo: (array ? @&quot;unsigned char[&quot; : @&quot;unsigned char&quot;) with: result];
				break;
			case 'v':
				//void
				result = [self appendTo: @&quot;void&quot; with: result];
				break;
			case ':':
				//selector
				result = [self appendTo: @&quot;SEL&quot; with: result];
				break;
			case '^':
				//pointer
				result = [self appendTo: @&quot;*&quot; with: result];
				break;
			case '@': {
				//object instance, may or may not include the type in quotes, like @&quot;NSString&quot;
				if (index + 1 &lt; [codeString length] &amp;&amp; [codeString characterAtIndex:index + 1] == '&quot;') {
					//we can get the exact type
					int endIndex = index + 2;
					NSString* theType = @&quot;&quot;;
					while ([codeString characterAtIndex:endIndex] != '&quot;') {
						theType = [NSString stringWithFormat:@&quot;%@%c&quot;, theType, [codeString characterAtIndex:endIndex]];
						endIndex++;
					}
					theType = [self appendTo: theType with: @&quot;*&quot;];
					result = [self appendTo: theType with: result];
				
					index = endIndex + 1;
				}
				else {
					//all we know is that it's an object of some kind
					result = [self appendTo: @&quot;NSObject*&quot; with: result];
				}
				break;
			}
			case '{': {
				//struct, we don't fully process these; just echo them
				index++;
				int numBraces = 1;
				NSString* theType = @&quot;{&quot;;
				while (numBraces &gt; 0) {
					char next = [codeString characterAtIndex:index];
					theType = [NSString stringWithFormat:@&quot;%@%c&quot;, theType, next];
					if (next == '{') {
						numBraces++;
					}
					else if (next == '}') {
						numBraces--;
					}
					
					index++;
				}
				result = [NSString stringWithFormat:@&quot;struct %@%@&quot;, theType, result];
				
				index--;
				break;
			}
			case '?':
				//IMP and function pointer
				result = [self appendTo: @&quot;IMP&quot; with: result];
				break;
			case '[':
				//array type
				array = YES;
				arrayString = @&quot;&quot;;
				result = [self appendTo: @&quot;]&quot; with: result];
				break;
			case ']':
				//array type
				array = NO;
				break;
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
				//for a statically-sized array, indicates the number of elements
				if (array) {
					arrayString = [NSString stringWithFormat:@&quot;%@%c&quot;, arrayString, nextChar];
				}
				break;
			default:
				break;
		}
	}
	
	return result;
}</pre>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/236/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
