Archive for the ‘Coding’ Category

Printable iPhone UI Design Template

Sunday, January 17th, 2010

Here is a printable template which is helpful in designing and sketching out iPhone app user interfaces. Each page has 3 iPhone screens with a small grid (each square = 32 iPhone screen pixels), and a space for notes.

Click here to get the image in PNG format (or right-click and choose ‘Save As…). You can open it up directly in Photoshop and print onto a standard 8.5×11″ sheet of paper. The image has .5″ margins around all sides and should print well on any standard desktop printer.

Enjoy.

HSV/HSB from UIColor

Thursday, December 31st, 2009

UIColor is a little limited in comparison to its Mac OS X counterpart NSColor. Ars Technica wrote up a handy set of additions which provide add-on methods for doing things like grabbing the -red, -green, and -blue component values from the underlying CGColorRef.

One thing the Ars code seemed to be missing was the ability to pull hue, saturation, and brightness values from a UIColor. So if you need to get those, here is an easy add-on category which piggybacks on Ars’ code.

Source code:

UIColor-HSVAdditions.h

UIColor-HSVAdditions.m

PS: I hope everyone has a fun New Years Eve. Be safe. :)

A-Star Obj-C Pathfinding Demo Updated

Monday, November 9th, 2009

A helpful denizen of the web pointed out a bug in the PathFind Demo code which caused the algorithm to hang under certain map situations. The bug has been fixed and the demo XCode project (with updated source code) can be downloaded here.

The FindPath demo is a sample XCode project which shows how to implement the A-Star pathfinding algorithm in Objective-C/Foundation/Cocoa. This updated version also has a nifty (but slow) animation option to watch the algorithm in action.

Demo Video

What’s in the works…

Friday, September 25th, 2009

Coming soon :

EasyBatch 1.6: EasyBatch is getting fine-tuned in 1.6, with a fresh coat of polish and internal improvements that include more efficient memory handling, engine tweaks, and several brand-spanking-new features including a built-in scaling calculator, and a text-based watermark generator. The 1.6 upgrade will be free for registered users, but will likely be coupled with a price increase for new licenses (EasyBatch is currently only $15!). So if you haven’t tried 1.5 yet, download EasyBatch and give it a go while the price is unchanged. If you find EasyBatch useful, please support its development before the official 1.6 release by registering your copy.

IconBurglar v1.2: Improvements to Drag ‘n Drop under Snow Leopard (10.6), improvements to the canvas and image viewer, better copy-and-paste support of images and sound resources, and more!

Multiplayer Mega BrickBash 3000: A new two player mode (with completely new gameplay and levels!) against either AI opponents or a friend across the ‘net.

MacMetronome v1.1: More beat samples and other improvements.

Stay tuned!

Cocoa Quickies: Get the size of a file

Thursday, September 3rd, 2009

Here’s a quick way to get the size of a file using NSFileManager, plus a method which can output a nicer “503kb” or “102.5MB”-style string based on the number of bytes.

Note: If you’re wondering why these numbers may not match the size you see in the Finder, well, there are a couple reasons, including changes in how the Mac OS X 10.6 Finder defines file sizes.

-(NSString*)niceSizeOfFileString:(int)bytes
{
    if(bytes<1024)
        return [NSString stringWithFormat: @"%d bytes", bytes];
    else if(bytes<1048576)
        return [NSString stringWithFormat: @"%dKB", (bytes/1024)];
    else
        return [NSString stringWithFormat: @"%.2fMB", ((float)bytes/1048576)];
}
-(int)sizeOfFile:(NSString*)path
{
    NSFileManager *fm = [NSFileManager defaultManager];
    NSDictionary *attr = [fm fileAttributesAtPath: path traverseLink: NO];
    int bytes = [[attr objectForKey: NSFileSize] intValue];
    return bytes;
}

Cocoa Quickies: Sort an NSDictionary by keys

Friday, August 21st, 2009

If you’ve ever needed to sort an NSDictionary by its keys, you’ll quickly discover that this functionality is missing from the NSDictionary class. This is because the order of keys in an NSDictionary is undefined (really, the concept has no meaning in an NSDictionary in the first place). So the basic process to follow is:

  1. Put the keys into an NSArray for ordering
  2. Sort the NSArray
  3. Traverse each key in the NSArray and obtain the -objectForKey

Here’s the code. (Note: this method uses its own bubble sort algorithm, but you could easily replace this with NSArray’s built-in sorting methods if you wanted to):

-(NSMutableArray*)bubbleSortDictionaryByKeys:(NSDictionary*)dict
{
	//this method takes an NSDictionary and performs a basic bubblesort
	//on its keys. It then returns those ordered keys as an NSMutableArray.
	//You can then traverse the original NSDictionary and retrive its
	//ordered objects by simply stepping through each key in the NSMutableArray.

	if(!dict)
		return nil;
	NSMutableArray *sortedKeys = [NSMutableArray arrayWithArray: [dict allKeys]];
	 if([sortedKeys count] <= 0)
		return nil;
	else if([sortedKeys count] == 1)
		return sortedKeys; //no sort needed

	//perform bubble sort on keys:
	int n = [sortedKeys count] -1;
	int i;
	BOOL swapped = YES;

	NSString *key1,*key2;
	NSComparisonResult result;

	while(swapped)
	{
		swapped = NO;
		for(i=0;i<n;i++)
		{
		key1 = [sortedKeys objectAtIndex: i];
		key2 = [sortedKeys objectAtIndex: i+1];

		//here is where we do our basic NSString comparison
		//This can be easily customized.
		//See the options for -compare: in NSString docs
		result = [key1 compare: key2 options: NSCaseInsensitiveSearch];
		if(result == NSOrderedDescending)
		{
		//we retain for good form, but these
		//objects should still be safely
		//retained by the dictionary:
		[key1 retain];
		[key2 retain];

		//pop the two keys out of the array
		[sortedKeys removeObjectAtIndex: i]; // key1
		[sortedKeys removeObjectAtIndex: i]; // key2
		//replace them
		[sortedKeys insertObject: key1 atIndex: i];
		[sortedKeys insertObject: key2 atIndex: i];

		[key1 release];
		[key2 release];

		swapped = YES;
			}
		}
	}

	return sortedKeys;
}

And here’s an example of how it can be used:

    NSDictionary *test = [NSDictionary dictionaryWithObjects:
                         [NSArray arrayWithObjects:
@"4",@"3",@"1",@"2",@"6",@"5",nil]
               forKeys:  [NSArray arrayWithObjects:
 @"dog", @"cat", @"apple", @"big bear", @"zebra", @"porcupine", nil]];
    NSMutableArray *keys = [self bubbleSortDictionaryByKeys: test];
    NSEnumerator *arrayEnum = [keys objectEnumerator];
    NSString *aKey = nil;
    NSString *str = @"";
    while((aKey = [arrayEnum nextObject]))
    {
        str = [str stringByAppendingString:
               [NSString stringWithFormat:
               @"\nKey: %@ -> %@", aKey, [test objectForKey: aKey]]];
    }
    NSLog(@"%@",str);

Output:

Key: apple -> 1
Key: big bear -> 2
Key: cat -> 3
Key: dog -> 4
Key: porcupine -> 5
Key: zebra -> 6

NSColorSpace is not thread safe

Tuesday, August 11th, 2009

There appears to be a bug within NSColorSpace, specifically the -initWithICCProfileData method. After quite a bit of testing to try and isolate the problem it appears that -initWithICCProfileData causes a rare but reproducible crash if it is not performed on the main thread. (Since AppKit drawing is considered thread-safe, it would be expected that NSColorSpace instances could be safely created and initialized from a secondary thread.)

You can reproduce this by running a test app which spawns two threads and repeatedly creates a new NSColorSpace instances with the color profile data from a bitmap obtained with NSBitmapImageRep imageRepWithContentsOfFile (in my case I was using an image with an embedded sRGB profile). The crash happens often enough to reproduce with some consistency. During the crash at least one of the threads is always within -initWithICCProfileData. An NSLock doesn’t seem to be a solution here, as the other thread may be doing something completely innocuous such as being in the middle of an NSLog.

The only workaround I have found is to either not use initWithICCProfileData within secondary threads or to perform the selector on the main thread. Doing that, I have been unable to coerce a crash.

I’m still looking into this, so there is a chance this could be the result of some other problem, but so far the evidence seems to show that NSColorSpace is not thread safe. Just wanted to post this information since I couldn’t find any details when I was searching. If anyone has any other info about this please let me know.

Cocoa Quickies: Store an NSColor with NSUserDefaults

Wednesday, August 5th, 2009

It might seem logical that NSColor would encode easily to NSUserDefaults using -setObjectForKey, but trying to do that will quickly raise an exception. It won’t work because it is not one of the core data types (NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary) which can be saved into property list (plist) files.

If you need to save an NSColor to your cocoa app’s preferences file, you’ll need to store the actual color values individually. Below is an example of how you can store a basic NSColor composed of RGBA values with NSUserDefaults. You can use these methods as they are or perhaps expand them to be additions to the NSUserDefaults class, whichever strikes your fancy:

-(void)userDefaultsSetColor: (NSColor*)color forKey:(NSString*)key
{
    NSArray *colorValues = [NSArray arrayWithObjects:
                            [NSNumber numberWithFloat: [color redComponent]],
                            [NSNumber numberWithFloat: [color greenComponent]],
                            [NSNumber numberWithFloat: [color blueComponent]],
                            [NSNumber numberWithFloat: [color alphaComponent]],
                            nil];
    [[NSUserDefaults standardUserDefaults] setObject: colorValues
                                              forKey: key];
}
-(NSColor*)userDefaultsColorForKey:(NSString*)key
{
    NSArray *colorValues = [[NSUserDefaults standardUserDefaults] objectForKey: key];
    if(colorValues && ([colorValues count] >= 4))
    {
        return [NSColor colorWithDeviceRed: [[colorValues objectAtIndex: 0] floatValue]
                                     green: [[colorValues objectAtIndex: 1] floatValue]
                                      blue: [[colorValues objectAtIndex: 2] floatValue]
                                     alpha: [[colorValues objectAtIndex: 3] floatValue]];
    }
    else
        return nil;
}

				

New! AppMaker v1.0 for OS X

Saturday, July 11th, 2009

AppMaker is a new freeware developer utility for Mac OS X. AppMaker creates a “double-clickable” OS X app from any executable binary or shell script. You can use it to create a genuine Mac application from a simple bash script (.sh) or GCC output file.

For a quick tutorial on using AppMaker, check out the steps below. Or you can download AppMaker v1.0 by clicking here. AppMaker is free and requires OS X 10.4 or later. (Note: for those of you visiting to check the status of Lotus and other BravoBug apps, please stay tuned, I’m working on getting them released as soon as possible. Thank you for visiting.)

A quick tutorial

In this tutorial we are going to write a very simple Bash shell script, and turn it into a double-clickable Mac OS X app. First let’s create our shell script.

Step 1. Open up your favorite text editor

Step 2. Write the shell script.

For this tutorial, we’re going to do something really simple: just create a folder and a “Hello, World!” text file on our desktop. Not very useful, but it will suffice for this demo. So paste or type the script into your text file:

#! /bin/bash
mkdir ~/Desktop/Hello\ World
echo "Hello, world!" > ~/Desktop/Hello\ World/README.txt

Step 3. Save your shell script (be sure it is saved as a plaintext file, with the ‘.sh’ file extension)

Step 4. Launch AppMaker. Select your script by pressing Select File… (or pressing Command-O). Set your details (such as the icon or version number) if you’d like to.

Step 5. Click Create Application…, give it a name, and save your app to the desktop.

Step 6. Try it out. Double-click the application and watch (hopefully) your cool Hello World folder and text file appear on your desktop. Easy as A-B-C. Just a few steps and you’ve got a Finder-friendly double-clickable Macintosh OS X application. Yay!

When .7 does not equal .7…

Monday, June 15th, 2009

Here’s a fun little experiment you can do which is an interesting way of revealing some ‘gotchas’ with the internal math used by your computer. Here’s the code:

    float x;

    x = .5;
    if(x == .5)
        NSLog(@"x is .5");
    else
        NSLog(@"Whoah! X is actually %f",x);
   
    x = .7;
    if(x == .7)
        NSLog(@"x is .7");
    else
        NSLog(@"Whoah! X is actually %f",x);
   
   
    x = .7;
    if(x == .7f)
        NSLog(@"x is .7");
    else
        NSLog(@"Whoah! X is actually %f",x);

You can run this yourself, or just check the actual output below.

 x is .5
 Whoah! X is actually 0.700000
 x is .7

At first glance this might seem odd. You would expect that .7 is .7 is .7. But such is not the case as far as your computer is concerned. In the second example (where the values are found to be unequal, and yet the output appears to show that they are equal), the lack of the “f” on the end of the comparison value means that the compiler interprets that literal .7 value as a double. And a float with .7 is not equal to a double with .7. The specifics of why this is so can be explained by floating point math ‘lack of precision’, which is all fine and dandy, but at first glance it sure seems strange that .7 does not always equal .7, especially since .5 in this case always equals .5!

This is a perfect example of why sometimes it is important to understand the inner workings of how the processor actually performs its math and value comparisons, especially with floating point variables. I find this kind of stuff fascinating because normally as I code I think of the computer as processing these kinds of instructions in the most fundamentally logical and reasonable way (ie, .7 = .7 = .7), and yet it’s fun to bump into these little situations where things don’t behave quite the way you might expect at first.

In other news, for those of you who are visiting to check the status of the recent updates announced for several of BravoBug’s shareware apps (EasyBatch, IconBurglar, Blackout etc.), I wanted to thank you both for your support in registering and also for your patience, I am working on getting those updates out as quickly as possible. Thank you for visiting, -Matt.