Begin main content

Load Interface Inspector's framework without modifying your Xcode project

Along the lines of Oliver Jones'€™ great tip about loading Reveal App'€™s* library into your iOS app without restarting the app or modifying your Xcode project, loading Interface Inspector'€™s** library into your Mac app at runtime is even easier thanks to Framework Bundles***. Simply add this into your .lldbinit:

command alias interface_inspector p (BOOL)[[NSBundle bundleWithPath:@"/Applications/Interface Inspector.app/Contents/Resources/InterfaceInspectorRemote.framework"] load]

and now at your lldb prompt just type "€œinterface_inspector" (or some unique part of that followed by tab) and then continue and you'€™ll be up and running.

* If you'€™ve been living in a cave you may not know about Reveal - the best thing for iOS developers since iOS 2.0.

** Interface Inspector is like Reveal for Mac apps (except not as good of course! No complaints about Interface Inspector, but you have to back your friends ;)

*** If you're thinking "€œwhy can't it be this easy on iOS?" - read Landon Fuller's excellent post: iOS Static Libraries Are, Like, Really Bad, And Stuff (Radar 15800975) and dupe his radar :)

05:30 AM, 20 Jan 2014 by Mark Aufflick Permalink | Comments (0)

GNUstep bleeding edge

For a client project I'm looking into Mac/Linux GUI cross platform options. Naturally GNUstep is high on my list. It's been a while (maybe 10 years) since I even played with GNUstep and I've struggled a bit getting all the latest things to compile together. So, like everyone else, I'm putting together a guide for how I did it since none of the other guides seem to be up to date (and I'm sure mine will be out of date shortly too!)

I'm installing on Ubuntu 12.04, but other Linux platforms will be very similar - just the dependencies might be different.

So firstly about those package dependencies. I've done so many apt-get installs that I've lost track exactly what I needed. Something a bit like this:

sudo aptitude install build-essential git subversion ninja cmake libffi-dev libxml2-dev libgnutls-dev libicu-dev libblocksruntime-dev libkqueue-dev libpthread-workqueue-dev autoconf libtool

Make sure you've uninstalled any older clang or libobjc libraries (otherwise you'll need to be very careful with configure args etc. to specify our compiled versions) and also any older version of libdispatch

Firstly we want the trunk version of llvm/clang. Grit your teeth, because we're going to have to use subversion:

cd
mkdir -p src/gnustep
cd src/gnustep
svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
cd llvm/tools
svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
cd ..
mkdir build
cd build
cmake ..
make -j4

Now add the following to your .bashrc etc:

export PATH=$PATH:~/src/gnustep/llvm/build/bin
export CC=clang
export CXX=clang++

Now reload your bashrc:

. ~/.bashrc

Check you can find clang:

which clang
clang -v
clang++ 0v

Now we want the latest gnustep libobjc2 with all the latest modern runtime goodies:

cd ~/src/gnustep
git clone https://github.com/gnustep/gnustep-libobjc2.git
cd gnustep-libobjc2
mkdir build
cd build
cmake ..
make -j4
sudo -E make install

Now add the following to your .bashrc:

export OBJCFLAGS="-fblocks -fobjc-runtime=gnustep"

cd ~/src/gnustep
git clone https://github.com/gnustep/gnustep-make.git
cd gnustep-make
./configure --enable-debug-by-default --with-layout=gnustep --enable-objc-nonfragile-abi
make
sudo -E make install

Now add the following to your .bashrc:

. /usr/GNUstep/System/Library/Makefiles/GNUstep.sh
. ~/.bashrc

Now we can start installing gnustep itself:

cd ~/src/gnustep
git clone https://github.com/gnustep/gnustep-base.git
cd gnustep-base
./configure
make -j4
sudo -E make install

If you get warnings about blocks during make, check that you don't have old libobjc libraries on your system. You can specify a particular libobjc library version when you build the gnustep-make package, but easier to just uninstall them.

Now lets run some tests.

make check

The gnustep-base check tests are very handy for making sure you have all the latest things. Warnings you should look out for are things like you haven't enabled blocks or subscripting. If you get warnings like that you should check your OBJCFLAGS etc. At this point I get no failures or skips:

7913 Passed tests 21 Dashed hopes

All OK!

Now we want the latest lib dispatch for all our GCD goodness:

cd ~/src/gnustep git clone git://github.com/nickhutchinson/libdispatch.git
cd libdispatch
sh autogen.sh
./configure CFLAGS="-I/usr/include/kqueue" LDFLAGS="-lkqueue -lpthread_workqueue -pthread -lm"
make clean make -j4
sudo -E make install sudo ldconfig

Now we can compile some test code from this post (http://lists.gnu.org/archive/html/discuss-gnustep/2012-12/msg00036.html) which I have pasted into a gist: https://gist.github.com/aufflick/5674798

clang `gnustep-config --objc-flags` `gnustep-config --objc-libs` -lobjc blocktest.m
./a.out

clang `gnustep-config --objc-flags` `gnustep-config --objc-libs` -lobjc -ldispatch -lgnustep-base Fraction.m helloGCD_objc.m
./a.out

And there we are! Ready to install the other gnustep-* modules from github.

08:10 PM, 29 May 2013 by Mark Aufflick Permalink | Comments (0)

Apple Operating Systems

I felt like pulling out my emulator collection this evening, so then I thought I'd see how many Apple OS's I could jam onto my iMac 27" screen at once. The answer is quite a lot, but fewer than I'd hoped—I may have to re-do the challenge including my second monitor.

Anyway, for your enjoyment, here it is. Click to expand:

The emulated systems are, left to right, top to bottom:

  1. Macintosh System 1.1 (showing the early Control Panel)
  2. Macintosh System 2.0.1 (running MacPaint)
  3. Macintosh System 3.3.0 (running the Scrapbook Desk Accessory)
  4. Macintosh System 6.0.0 (showing the newer Control Panel)
  5. Macintosh System 8.5 (running CyberDog)
  6. Apple 1 with a simple Hello World program entered into the WOZ Monitor
  7. Dos 3.3 (running Beagle Bros Apple Mechanic)
  8. UCSD Pascal OS
  9. Prodos 1.1
  10. Apple /// SOS
  11. The Lisa Office System (running LisaCalc)
  12. Newton OS (running on an eMate 300)
  13. NextStep 3.3 (running Mail.app - not strictly an Apple OS I guess)

07:58 AM, 18 Oct 2011 by Mark Aufflick Permalink | Comments (0)

Swipe Conference—apparently quite successful!

Hi all. I can't believe I haven't posted a blog post in six months. That's just embarrassing! I've been a little busy, not least with Swipe Conference. If you missed it, Swipe Conference ran ran last month in Melbourne (Australia, not Florida ;) packed full of awesome talks about iOS and Mac software development, design and user experience. Thanks to all our amazing speakers and delegates who made it such an enjoyable time.


Congratulations again to our Swipe Award winners: Best iPhone Application, AFL Aussie Rules Live 2011 from SportsMate Mobile; Best iPad Application, The SMH for iPad and The Age for iPad from Fairfax Digital; and Best Mac Application, Ortelius from Mapdiva

                         

We will progressively put some of the video footage from Swipe online thanks to our friends at Eventer : http://swipeconference.eventer.com/

Finally, co-organisers Sean, Jake and myself would like to express our sadness at the passing of Steve Jobs. He has helped shape our lives for the better. Hopefully we can continue to give others the joy and excitement that his life has brought us.

07:49 PM, 10 Oct 2011 by Mark Aufflick Permalink | Comments (0)

Speaking at Mobile Camp OZ on March 1st

I may be entering the lion's den judging by the majority of Mono/.Net talks, but nevertheless I am giving an iOS zero to hero in 55 minutes talk at Mobile Camp OZ in historic (ie. remote and cold ;) Bathurst. It's a free two day conference, so why don't you come along? http://www.mobilecampoz.com/. You could win one of these ride-on Eski's, now that would be awsm!

On the topic of conferences, not sure why I didn't mention this earlier - Swipe Conference! Australia's first iOS and Mac developers conference organised by Jake MacMullin, Sean Woodhouse and yours truly.

02:09 AM, 28 Apr 2011 by Mark Aufflick Permalink | Comments (0)

Apple Push Notifications Talk—Screen/Audio recording now available

Thanks again to the guys at the Apple University Consortium for inviting me to speak at /dev/world 2010. The screen/audio recordings are now available. I have linked to them (and the rest of the /dev/world presentations) on my APNS talks page:

http://mark.aufflick.com/talks/apns

07:00 PM, 02 Mar 2011 by Mark Aufflick Permalink | Comments (0)

Making a fat static library for iOS device and simulator

Some third party iOS library providers (I'm looking at you Omniture) provide separate static library archives for simulator (i386) and device (armv6 and or armv7).

That's a pain since you either change them manually or set the linking flags on different Xcode targets to use the appropriate library (whereas normally with libraries and frameworks you just drag it into your project and you're done).

Instead, you can build your own fat (multi-architecture) library from the provided archives and Xcode will link against the appropriate architecture segment (flagrantly ignoring Erik's dire predictions about testability and your personality ;)

We achieve this using the lipo tool, eg:

lipo -output libOmnitureAppMeasurement-fat.a -create -arch armv6 libOmnitureAppMeasurement-iPhoneDevice.a -arch l386 libOmnitureAppMeasurement-iPhoneSimulator_4_0_GM.a

Update:

The latest Omniture libraries, available via the Omiture SiteCatalyst admin console, now contains armv6 and armv7 architectures. Oddly, that means that they provide two archives—one regular i386 archive (with no fat header) for the simulator and one fat archive for the device with armv6 and armv7 segments. Since the device archive headers now specify the archives already, we don't need to tell lipo anything other than the archive file name.

lipo -output libOmnitureAppMeasurement-fat.a -create libOmnitureAppMeasurement-iPhoneDevice.a -arch i386 libOmnitureAppMeasurement-iPhoneSimulator.a

11:43 PM, 18 Nov 2010 by Mark Aufflick Permalink | Comments (1)

Speaking at /dev/world 2010

/dev/world is a conference run by the Australasian Apple University Consortium (AUC). The AUC has been around since the Mac was launched in 1984 to promote and foster development of Apple platforms.

This year the AUC conference is in Melbourne on September 28th-29th and I will be one of the speakers. Here's my bit in the program:

Push Notifications - Device, Protocol and Server
Speaker: Mark Aufflick
Target Audience: Intermediate

Apple Push Notifications are an integral part of many applications, from games like "Words With Friends" to VOIP call notification, but for the non-expert developer they can be a source of mystery. Apple's "Local and Push Notification Programming Guide" provides details of the binary protocol, SSL certificates and other details which are hardly beginner material. Additionally the guide makes little mention of correct UTF encoding and other small details which create more difficulty for those unfamiliar with data encodings etc. And finally a persistent server is required which can handle the protocols. This talk will take attendees through: an understanding of the service overall; the protocol and its limitations; responding to notifications in the iOS application; approaches to implementing a server in Perl, Python or Ruby.

Bio:
Mark Aufflick has been involved in the Apple industry since his first job in 1995 and finally put his Computer Science degree to use becoming a freelance developer in 2000. Since then he has developed back end, web and gui applications for various Unix platforms, MacOS and iOS - for both corporate giants and small businesses. Mark has presented on programming topics in fora such as Sydney University's Web Engineering Group and CocoaHeads. These days Mark is an iOS and Mac developer with his company Pumptheory as well as the convenor of Sydney CocoaHeads.

I'm really looking forward to meeting the other presenters and delegates! If you're attending, let me know on twitter - I'm @markaufflick.

12:36 AM, 06 Sep 2010 by Mark Aufflick Permalink | Comments (0)

Filtering Growl notifications

Now that I work full time on my Mac I have Skype, Notify and any number of other apps telling me stuff via Growl. One of the great things about having everything centralised through a single notification mechanism is that you can easily choose what notifications you want to see.

Growl already has a great way to choose notifications by turning Apps on or off and notification types as registered by the Apps. But it doesn't have any way to filter based on the content of the notification—e.g. if I want to see when some Skype users log on but not others.

So since Growl is open source I took matters into my own hands. I don't have a UI yet, and haven't forked the repository, but for now here's a quick patch.

The UI is you use Apple's Plist editor to add an array with key "GrowlIgnorePredicates" to com.Growl.GrowlHelperApp.plist in your Library/Preferences directory :) Here are the keys, see NSPredicate docs for predicate string syntax. If you have no idea what I just said you'll have to wait for the UI I'm afraid!

  • ApplicationName
  • NotificationTitle
  • NotificationDescription
  • And here is the patch:

    diff -r 9f9a8561261a Core/Source/GrowlApplicationController.m
    --- a/Core/Source/GrowlApplicationController.m	Sun Aug 01 10:35:51 2010 -0400
    +++ b/Core/Source/GrowlApplicationController.m	Wed Aug 04 13:18:37 2010 +1000
    @@ -592,6 +592,21 @@
     		[pool release];
     		return GrowlNotificationResultDisabled;
     	}
    +    
    +    GrowlPreferencesController *preferences = [GrowlPreferencesController sharedController];
    +    
    +    // Mark Aufflick hack - needs UI    
    +    NSArray *ignorePredicates = [preferences objectForKey:GrowlIgnorePredicates];
    +
    +    if ([ignorePredicates isKindOfClass:[NSArray class]]) {
    +        for (NSString *predString in ignorePredicates) {
    +            NSPredicate *p = [NSPredicate predicateWithFormat:predString];
    +            if ([p evaluateWithObject:dict]) {
    +                NSLog(@"ignoring notification due to predicate: %@", p);
    +                return GrowlNotificationResultDisabled;
    +            }
    +        }
    +    }
     
     	NSMutableDictionary *aDict = [dict mutableCopy];
     
    @@ -642,8 +657,6 @@
     		value = [NSNumber numberWithInt:priority];
     	[aDict setObject:value forKey:GROWL_NOTIFICATION_PRIORITY];
     
    -	GrowlPreferencesController *preferences = [GrowlPreferencesController sharedController];
    -
     	// Retrieve and set the sticky bit of the notification
     	int sticky = [notification sticky];
     	if (sticky >= 0)
    diff -r 9f9a8561261a Core/Source/GrowlPreferencesController.h
    --- a/Core/Source/GrowlPreferencesController.h	Sun Aug 01 10:35:51 2010 -0400
    +++ b/Core/Source/GrowlPreferencesController.h	Wed Aug 04 13:18:37 2010 +1000
    @@ -39,6 +39,7 @@
     #define LastKnownVersionKey			XSTR("LastKnownVersion")
     #define GrowlStickyWhenAwayKey		XSTR("StickyWhenAway")
     #define GrowlStickyIdleThresholdKey	XSTR("IdleThreshold")
    +#define GrowlIgnorePredicates       XSTR("GrowlIgnorePredicates")
     
     CFTypeRef GrowlPreferencesController_objectForKey(CFTypeRef key);
     CFIndex   GrowlPreferencesController_integerForKey(CFTypeRef key);

11:47 PM, 03 Aug 2010 by Mark Aufflick Permalink | Comments (0)

Using blocks to simplify custom view drawing

Commonly when you are drawing a custom Cocoa view, you will be creating paths, filling and stroking them etc. You might even be drawing a similar shape a number of times. A naive approach to drawing five round rects with shadows might look like this:

#defineDDOFFSET 10
#defineDDWIDTH 50

- (void)drawRect:(NSRect)dirtyRect {

    [NSGraphicsContext saveGraphicsState];

    for (inti=0 ; i < 5 ; i++)
    {
        // offset and put onto pixel boundary
CGFloattop = [self frame].size.height - 0.5 - DDOFFSET;
        CGFloatleft = 0.5 + (DDWIDTH * i) + (DDOFFSET * i) + DDOFFSET;
                
        NSRectborderRect = NSMakeRect(left,
                                       DDOFFSET,
                                       DDWIDTH,
                                       top - DDOFFSET);
        
        NSBezierPath *borderPath = [NSBezierPath bezierPathWithRoundedRect:borderRect
                                                                   xRadius:5
                                                                   yRadius:5];
        
        NSColor *borderColor = [NSColor grayColor];
        
        NSShadow *borderShadow = [[NSShadow alloc] init];
        [borderShadow setShadowOffset:NSMakeSize(2.0, -2.0)];
        [borderShadow setShadowBlurRadius:2.0];
        [borderShadow setShadowColor:[[NSColor blackColor] colorWithAlphaComponent:0.3]];
        
        NSColor *fillColor = [NSColor whiteColor];
        
        // do the drawing
        [borderColor set];
        [borderShadow set];
        [borderPath stroke];
        [fillColor set];
        [borderPath fill];
    }
    
    [NSGraphicsContext restoreGraphicsState];
}

(Note these examples are all using garbage collection).

Hopefully, it should occur to you that, amongst other issues, this is needlessly inefficient because a bunch of objects are being created and destroyed each time the view is dirtied. So we want to move the creation of objects into a separate method that is called when the view is created, store the paths in an array and the drawRect would then just have to set the colours, stroke the paths, etc. Something like this:

@interfaceDrawDemo2View : NSView {
    NSColor *borderColor;
    NSShadow *borderShadow;
    NSColor *fillColor;
    NSMutableArray *borderPaths;
}

@end
@implementationDrawDemo2View#defineDDOFFSET 10
#defineDDWIDTH 50

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        borderColor = [NSColor grayColor];

        borderShadow = [[NSShadow alloc] init];
        [borderShadow setShadowOffset:NSMakeSize(2.0, -2.0)];
        [borderShadow setShadowBlurRadius:2.0];
        [borderShadow setShadowColor:[[NSColor blackColor] colorWithAlphaComponent:0.3]];
        
        fillColor = [NSColor whiteColor];
        
        borderPaths = [[NSMutableArray alloc] initWithCapacity:5];
        
        for (inti=0 ; i < 5 ; i++)
        {
            // offset and put onto pixel boundary
CGFloattop = [self frame].size.height - 0.5 - DDOFFSET;
            CGFloatleft = 0.5 + (DDWIDTH * i) + (DDOFFSET * i) + DDOFFSET;
            
            NSRectborderRect = NSMakeRect(left,
                                           DDOFFSET,
                                           DDWIDTH,
                                           top - DDOFFSET);
            
            NSBezierPath *borderPath = [NSBezierPath bezierPathWithRoundedRect:borderRect
                                                                       xRadius:5
                                                                       yRadius:5];
            
            [borderPaths addObject:borderPath];
        }
    }

    returnself;
}

- (void)drawRect:(NSRect)dirtyRect {

    [NSGraphicsContext saveGraphicsState];

    for (NSBezierPath *pathin borderPaths) {
                
        // do the drawing
        [borderColor set];
        [borderShadow set];
        [path stroke];
        [fillColor set];
        [path fill];
    }
    
    [NSGraphicsContext restoreGraphicsState];
}

@end

That's mildly painful, and disconnects the meaning of the above code somewhat, but it's not too bad. What, though, if there are other shapes that require different handling - well they will need their own array and drawing code. Then we want to subclass the view and the subclass wants to draw circles, etc. etc. Your view will become messy and very specific. Also in a real example I'd probably need more save/restore graphics states, but here the shadow on the fill isn't important.

Thankfully we can use blocks, which are what some other languages call closures, to keep the efficiency of separating the execution time of the drawing code while keeping it all together in a very general way. We end up with something almost identical to the first naive implementation, but the drawing section at the end goes into a block in an array, and the drawRect simply executes all those blocks:

@interfaceDrawDemoBlocksView : NSView {
    NSMutableArray *drawingBlocks;
}

- (void)addRoundRect: (int)num;

@end
@implementationDrawDemoBlocksView#defineDDOFFSET 10
#defineDDWIDTH 50

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        drawingBlocks = [[NSMutableArray alloc] initWithCapacity:5];

        for (inti=0 ; i < 5 ; i++)
            [self addRoundRect:i];
    }
    returnself;
}

- (void)drawRect:(NSRect)dirtyRect {

    for (void *(^block)(void) indrawingBlocks)
    {
        [NSGraphicsContext saveGraphicsState];
        block();
        [NSGraphicsContext restoreGraphicsState];
    }
}

- (void)addRoundRect: (int) num
{
    // offset and put onto pixel boundary
CGFloattop = [self frame].size.height - 0.5 - DDOFFSET;
    CGFloatleft = 0.5 + (DDWIDTH * num) + (DDOFFSET * num) + DDOFFSET;
    
    NSRectborderRect = NSMakeRect(left,
                                   DDOFFSET,
                                   DDWIDTH,
                                   top - DDOFFSET);
    
    NSBezierPath *borderPath = [NSBezierPath bezierPathWithRoundedRect:borderRect
                                                               xRadius:5
                                                               yRadius:5];
    
    NSColor *borderColor = [NSColor grayColor];
    
    NSShadow *borderShadow = [[NSShadow alloc] init];
    [borderShadow setShadowOffset:NSMakeSize(2.0, -2.0)];
    [borderShadow setShadowBlurRadius:2.0];
    [borderShadow setShadowColor:[[NSColor blackColor] colorWithAlphaComponent:0.3]];
    
    NSColor *fillColor = [NSColor whiteColor];
    
    [drawingBlocks addObject:[^{

        // do the drawing
        [borderColor set];
        [borderShadow set];
        [borderPath stroke];
        [fillColor set];
        [borderPath fill];
        
    } copy]];
}

@end

You can also see how this would work really well if we subclassed this view - all subclasses could simply push a block onto the array to request some work to be done during the drawRect phase.

You'll note how the block itself isn't added to the array, but a copy of it. That's because by default the storage for the context embodied in the block is only valid for the scope in which it is created. If we want to execute the block after the scope is gone we need to copy it.

If you found this useful you might also like Drew McCormack's excellent article 10 Uses for Blocks in C/Objective-C.

11:36 PM, 29 May 2010 by Mark Aufflick Permalink | Comments (0)

iPad gets back to the priorities of the first Macintosh

The first Mac I ever used was a Mac 128, when my Dad brought one home as part of the ground breaking Apple Test Drive promotion. It booted into the Finder quickly even though it used a floppy. It only ran one program at once, so programs (mostly) started and exited quickly and didn't interact. It had a fixed screen size so everyone's experience was the same. There were desk accessories that gave access to limited functionality while applications were running.

Sounds a lot like the iPad (except bigger and black and white - and of course no 3G ;).

Seriously, it's Steve Job's core vision all over again. Steve Jobs didn't want the Apple ][ to have any expandability, it was Steve Wozniak who convinced him (correctly) that computers were still very much a hobbyist device and need expandability. The original Mac wasn't supposed to have upgradeable ram - it was the engineers (Burrell Smith I think) who secretly made the circuit board easily upgradeable.

Only now, the hardware and connectivity reality has caught up with Jobs' reality: hardware is cheap, expendable and compact - and Apple makes the best. Once again another insanely great device is going to change the place computers have in our lives.

07:08 PM, 27 Jan 2010 by Mark Aufflick Permalink | Comments (1)

Debugging release/autorelease issues in Cocoa

So your code crashes with an EXC_BAD_ACCESS in objc_msgSend and there is *none* of your own code in the stack trace. Bummer. Since all we know from objc_msgSend is that it's trying to call a method on an object. Since we got EXC_BAD_ACCESS you can bet your bottom dollar that it's attempting to call a method on a freed pointer, so there's no obvious way of finding out what the object was. We can, though, easily find the method. Read Greg Parker's excellent post So you crashed in objc_msgSend(). For the iPhone simulator on my Mac I need to do this at the gdb prompt to decode the eax register:

(gdb) x/s $ecx
0x980530c4:	 "release"
you can see that the selector in the second argument is "release". Now we're getting somewhere, we know an already freed object is trying to be released. Since there is none of our code in the stack trace it's a fair bet that it's happening when the autorelease pool is releasing.

There are a few tricks in your toolbox for tracking down over-released objects. There's the NSZombieEnabled, NSAutoreleaseFreedObjectCheckEnabled and other environment variables which will give you better logging rather than just crashing.

I've found this is not always reliable (logs from the above builtin debug options showed that the over-release was on an NSCFDate object, when in fact it was an NSNumber). Sometimes you also just want to trace through exactly what is happening with your retain/release/autorelease cycles. That's what we're about to achieve here.

Ok, so you have a unit test that replicates this problem right? I use the excellent GHUnit by Gabriel Handford. If not you'll have to play around a bit to narrow down your problem code. In my case, I wanted to confirm that a particular unit test was failing during the autorelease pool release. Best way is to wrap the offending code in a new autorelease pool. Then it will be freed inside your code, which you will see in the stack trace, and confirm you have found the reason. My unit test now looks like:

(Note that the code examples, embedded in github gists, are not showing up in my RSS feed. I'll fix that later, but for now please read the original post)

Now when I fail with EXC_BAD_ACCESS my stack trace looks like this:

Where line 91 of CJTestCJCard.m is the [pool release] call above. So something is being added to the autorelease pool, and is *also* being fully released, or maybe it's being added to the pool more times than it is being retained. There doesn't seem to be a way to interrogate the contents of the autorelease pool (which is a shame) but we log some really useful info by overriding a few methods, like NSObject's release and autorelease methods, so we can see when things are being added to the pool and when things are being released. This is some funky stuff, but since we're only doing it in our unit test class, not code we're going to release you can sleep soundly at night. Here's how I effected logging in release and autorelease.

Add this to the top of your unit test class, before your current @implementation:

Now in your unit test class @implementation, you can use the setupClass method to effect the method implementation switcharoo:

Now your log will be filled with log lines like:

This can help when tracking down tricky releasing bugs. Note that not all classes seem to comply. For instance I see plenty of log lines for NSCFString, but never any release lines. I assume that NSCFString release implementation is a bit different since it's a toll free bridged object - getting that to log is an exercise left for the reader!

If you're interested in the functions I used above to interact with the runtime, check out the Introduction to The Objective-C Programming Language and Objective-C Runtime Reference. Note that the code above works fine in the iPhone simulator. It should be fine on 64 bit Mac apps, but you may need to diddle the method structs manually in 32 bit Mac apps since they use the legacy Objective-C runtime (which you can read about in the Objective-C 1 Runtime Reference).

Also note it won't work on the iPhone itself, so to save constantly commenting out code, you can wrap the offending code in #if TARGET_IPHONE_SIMULATOR #endif pairs.

08:38 PM, 13 Jan 2010 by Mark Aufflick Permalink | Comments (2)

Book Review: iPhone SDK 3 Visual Quickstart Guide


CocoaHeads Sydney member Duncan Campbell has just published a book with PeachPit press titled "iPhone SDK 3 Visual Quickstart Guide".

Like all of Peachpit's "Visual Quickstart Guides", the book is mostly broken into two columns - text and images. At first I thought it would suck! As soon as I got into it though, I quite liked the thin column. It has readability like a newspaper, although it did make following inline code a little tedious.

The book covered all the basics you need for making a great app, and made some tricky tasks simple - like custom cells and multi-touch.

It avoids a common approach of many intro books where they continually build into an ever evolving single app. Instead, each example is short and entirely standalone. I have to say it was refreshing - it avoided wasting time in frivolities and allowed the author to introduce concepts at the time he chose, rather than the time it was needed to continue building the app.

I also appreciated the time spent on one of the most important rools - the Xcode interface. Even I learned a handy Xcode shortcut!

The choice to use code for UI layout instead of interface builder makes the writing easier to follow, no enless 'click here, control click and drag here...' and also avoids those madenning bugs where you've missed a step but can't easily compare the compound result. Similarly, the continual tweaks to IB won't invalidate the examples.

I also appreciated how each example was standalone - building and running an interesting looking example didn't rely on carefully building examples stretching back through previous chapters.

Two extra chapters can be downloaded as PDFs from the Peachpit press website once you have the book covering the Address Book api and the Media apis. The latter is very useful - covering saved images, using the camera and playing audio and video.

While this is a book for people starting out with iPhone programming, it's not for people who have never programmed before. If you have programmed before but don't know at least the bare basics of one of C, C++, Objective-C then I would suggest completing an introduction to Objective-C first. Apple has one and there are lots of great books.

One of the positives above is that the use of code to create UI controls is repeatable, easy to error check and shows how it all works. Once you start building apps, though, you'll use Interface Builder a lot. You'll need to brush up on that after completing this book. Again, Apple has one and there are lots of great books! Aaron Hillegass's Cocoa Programming for Mac OS X will cover both Objective-C and Interface Builder really well - and you'll learn how to write MacOS X apps to boot!

So in summary, it's a great book. I enjoyed it and you hopefully will too! Available at Amazon and all good bookstores :)

04:33 AM, 25 Oct 2009 by Mark Aufflick Permalink | Comments (2)

CocoaHeads Sydney October Meetup - Thursday October 1st - Blocks and Beer!

Hooray - it's that time of month again!

Chris Suter will be giving a talk on Blocks and perhaps some other shiny things he learnt at WWDC. It promises to be a great topic so come and heckle! There are a few new people coming so please be welcoming :)

As always, bring along any Mac related projects you want to show off
or ask for advice on.

IMPORTANT! Room has changed.

It will now be in CB02.05.32.

That's Building 2, Level 5, Room 32. You can access building 2 via the main entrance. This will be our room for the rest of the year.

You might find the UTS Broadway campus map useful: http://is.gd/3l1iu

Thanks to David Morrison for sorting this out.

A gleaming pile of laptops will surely guide you.

The Australian CocoaHeads mailing list is at http://groups.google.com/group/cocoaheadsau

08:49 AM, 16 Sep 2009 by Mark Aufflick Permalink | Comments (0)

CocoaHeads Sydney - room change for tonight (August)

It will now be in CB04.02.33.

Thats Building 4, Level 2, Room 33. Its the new refurbished Science
building, corner of Thomas and Harris st, diagonally opposite ABC.

You might find the UTS campus map useful: http://is.gd/228P5

Thanks to David Morrison for sorting this out.

Mark.

02:47 AM, 06 Aug 2009 by Mark Aufflick Permalink | Comments (0)

CocoaHeads Sydney - Meetup This Thursday August 4th

After last month's shemozzle we're back on track with our usual moderate level of organisation for CocoaHeads.

The August meet is this coming Thursday (we always meet the first Thursday). Venue is the same as the last three months: UTS Broadway CB10.07.114 ie. Building 10, Level 7, Room 114

Google map: http://is.gd/228MG
UTS Broadway campus map: http://is.gd/228P5

Time: 6:30pm or whenever

We have a couple of short/lightning talks in planning - one is confirmed that I am excited to share with you. Continuing our great tradition of cross-pollonating with fpsyd, Alan Rogers is going to give us a lightning talk about Objective-J and Cappacino. Objective-J is a language inspired by Objective-C and implemented on top of JavaScript. Cappacino is a framework based on that. Alan met up with the guys behind Objective-J at WWDC this year.

As always we will be retiring for beers once the formal part of proceedings has finished.

Look forward to seeing you all there!

09:25 AM, 04 Aug 2009 by Mark Aufflick Permalink | Comments (0)

Adding Apple Remote Support to your Cocoa App

Here is the presentation I gave at last month's CocoaHeads:

Or you can download the pdf from the CocoaHeads AU Google group: apple_remote.pdf.

08:24 PM, 04 May 2009 by Mark Aufflick Permalink | Comments (0)

CocoaHeads Sydney - May 7th 2009

CocoaHeads Sydney is steaming along with our fourth monthly meeting on the trot this Thursday.

Last month at CocoaHeads Sydney I gave a lightning talk showing how to add Apple IR support to your Cocoa app. I have uploaded the slides to the files section of the google group. In the presentation I also showed how I used the LaTeX beamer class to make pdf slides, and I used the open source SplitShow application to give the presentation (using my Apple IR support of course!) You can get SplitShow from the google code project but you'll have to build from the trunk to get the IR support which has not yet been included in a release.

We also had Ben Hill show us the impressive prototype of an OpenGL iPhone game he put together using cocos2d.

This month our very own Jude Sutton will be giving us a presentation on the Authorisation Services and related APIs.

This month's details:

When: Thursday May 7th, 6:30pm
Where: UTS Broadway CB10.07.114. ie. Building 10, Level 7, Room 114
Calendar:

All details are published monthly on the CocoaHeads AU google group.

Hope to see you there!

08:12 AM, 03 May 2009 by Mark Aufflick Permalink | Comments (0)

CocoaHeads Sydney - March 5th 2009

I'm excited our Sydney CocoaHeads meetup next week, looking forward to expanding on our great start of 20 odd people (that is 20 or so people, although many of us may also be odd...).

André's talk last month was an interesting delve into Objective-C internals and creative ways to make use of that knowledge. (slides).

This month I am pleased to announce that Nathan Day, who was in our meeting last month, will be presenting something that instead saves you from having to know about some of the nastier internals of the Cocoa framework&#8212his extensive collection of public frameworks.

Nathan was guest speaker at Brisbane CocoaHeads last Thursday and has agreed to make a repeat performance for us.

The location will again be UTS although the room may be different as the semester is approaching, stay tuned for details.

There are details about subscribing to the google calendar on a page in our group: http://is.gd/kEtW

Or you can use this link to add the March meeting to your own calendar: http://is.gd/kEud

I'll update the calendar meeting with the room details etc. when I have them and will also email the cocoadev list etc. closer to the day. Looking forward to seeing you all there!

06:59 AM, 24 Feb 2009 by Mark Aufflick Permalink | Comments (0)

CocoaHeads Sydney - February 5th 2009

After the very successful, and inaugural, Christmas beers event held by Sydney CocoaHeads in December, our first meetup for 2009 will occur on Thrusday February 5th.

What is CocoaHeads?

CocoaHeads is a global collection of groups devoted to discussion of Apple Computer's Cocoa Framework for programming on MacOS X. During monthly meetings, members present on their projects and offer tutorials on various programming topics.

February, the ever interesting André Pang will be speaking. You can find more details about the Sydney meetup by joining our Google Group: Sydney CocoaHeads.

There is also a calendar you can subscribe to:

    

Or add just this upcoming meeting to your calendar:

09:06 AM, 21 Jan 2009 by Mark Aufflick Permalink | Comments (0)

heads up 'tunes featured on iLoveMacApps.com

James Powell has featured heads up 'tunes on his iLoveMacApps.com and also has some neat feature suggestions.

I'm not sure where the slowdown he is seeing is coming from so I'll quiz him on that, but clicking the song and hiding the dock icon are good ideas.

He has a pretty eclectic playlist :)

06:51 PM, 19 Jan 2009 by Mark Aufflick Permalink | Comments (0)

XML

Blog Categories

software (41)
..cocoa (23)
  ..heads up 'tunes (5)
..ruby (6)
..lisp (4)
..perl (4)
..openacs (1)
mac (21)
embedded (2)
..microprocessor (2)
  ..avr (1)
electronics (3)
design (1)
photography (26)
..black and white (6)
..A day in Sydney (18)
..The Daily Shoot (6)
food (2)
Book Review (2)

Notifications

Icon of envelope Request notifications

Syndication Feed

XML

Recent Comments

  1. Mark Aufflick: Re: the go/Inbox go/Sent buttons
  2. Unregistered Visitor: How do make a button to jump to folder
  3. Unregistered Visitor: Note I've updated the gist
  4. Unregistered Visitor: umbrello is now an available port on macPorts
  5. Unregistered Visitor: Updated version on Github
  6. Unregistered Visitor: Modification request.
  7. Unregistered Visitor: Accents and labels with spaces
  8. Unregistered Visitor: Mel Kaye - additional info
  9. Unregistered Visitor: mmh
  10. Mark Aufflick: Thank you