Forgetting Keychains

Daniel Jaikut asked why the default keychain in OS X keeps getting changed, which I’ve also noticed, as have a few other people. It seems to be related to XCode and usually manifests itself as a code signing error. If you look at the provisional profiles tab in XCode’s organizer window, you’ll see a warning about a missing certificate.

I found a very simple manual fix for it. Add the following script to XCode’s script menu:


#!/bin/sh
/usr/bin/osascript - < <***
tell application "Keychain Scripting"
	set current keychain to keychain named "mike.keychain"
end tell
***

If XCode complains about a missing certificate, run that script from the menu and you’ll be OK.

Rewriting code without fear

Over the last few days, I’ve been rewriting some major pieces of ICanHasCheezburger.app to simplify and clean up the way I handle movies. Currently I use a single image view, which is set to a ‘play’ image for movies, which then open in the browser when clicked. I’m changing it to swap between the image view for displaying images and a web view in which I open movies.

In addition, I’ve cleaned up and simplified the way I deal with the RSS feeds I obtain the images from. Previously, I had a single FeedController class, which stored the entries obtained from a CXMLDocument as an array of CXMLNodes. To display an image, open the web page, or play a movie, I had to query the FeedController for an element of the current item.

To clean it up, my FeedController now uses an array of FeedItem objects, with properties such as permalink, image URL, movie URL, and title. I now pass a FeedItem to my root view, which uses it to decide whether to display an image or movie without having to go back and query the FeedController.

I found it to be a lot easier & cleaner to use NSXMLParser, so I can create a FeedItem for each RSS item directly rather than have to manipulate the CXMLDocument, extract each CXMLNode, and create a FeedItem for it.

Until now I’ve never used XCode’s Snapshot feature. Since I use Subversion, I figured I could simply check out an earlier revision. Before I started rewriting all of that code, I saved a snapshot. It shows exactly what has changed since the snapshot and makes it very easy to revert if something goes wrong. It’s very similar to checking in to Subversion or reverting to an earlier revision, but it’s a lot faster and more convenient. I find it very liberating to be able to make a major change like this and not have to worry about messing up, since I can easily go back to the way it was.

Snapshots

Useful XCode tricks

XCode provides several ways to make your work easier by cutting down on repetitive typing. The simplest (from a usage standpoint) is text macros. You simply type an abbreviation and hit Escape to substitute it. A text macro can have variable substitutions where you can add text.

I’ve seen a few contradictory articles telling how to add your own text macros, which don’t work in XCode 3.1, but here’s how I was able to get it to work.

First, open /Developer/Applications/Xcode.app/Contents/PlugIns/ and look for TextMacros.xctxtmacro. Make a copy of TextMacros.xctxtmacro and place it in ~/Library/Application Support/Developer/Shared/XCode/Specifications. You may need to create the Specifications folder if it doesn’t exist.

In the copy of TextMacros.xctxtmacro, go to Contents/Resources and edit any of the .xctxtmacro files such as C.xctxtmacro (anything defined there also works in C++ and Objective-C). Any changes here will override the version in XCode. If you only modify one of the macro files, you can delete the others from the copy.

My development team is supposed to add a standard copyright header to each source file. I created a macro that allows me to type ‘stdcopy’ and have it expand to the entire header, with highlighted items that I can tab to and add text. I also added a ‘history’ macro which adds a history comment below the standard copyright block.

For those two macros, I added the following definitions to C.xctxtmacro:

        {
            Identifier = c.stdcopy;
            BasedOn = c;
            IsMenuItem = YES;
            Name = "Standard Copyright Header";
            TextString = "//---------------------------------------------------------------------\n// Copyright (c) $(YEAR) $(ORGANIZATIONNAME).  All rights reserved.\n// Reproduction or transmission in whole or in part, in any form or\n// by any means, electronic, mechanical or otherwise, is prohibited\n// without the prior written consent of the copyright owner.\n//\n// < #summary#>\n//\n// < #remarks#>\n//\n// Date\t\t\tRelease\t\t\tTask\t\tWho\t\tSummary\n// =====================================================================\n// < #date#>\t\t< #release#>\t\t< #task#>\t\t< #who#>\t\t< #summary#>\n//---------------------------------------------------------------------\n";
            CompletionPrefix = stdcopy;
            IncludeContexts = ( "xcode.lang.c", "xcode.lang.java" );    // this works in Java too
        },

        {
             Identifier = c.history;
             BasedOn = c;
             IsMenuItem = YES;
             Name = "History Comment";
             TextString="// < #date#>\t\t< #release#>\t\t< #task#>\t\t< #who#>\t\t< #summary#>\n";
             CompletionPrefix = history;
             IncludeContents = ( "xcode.lang.c", "xcode.lang.java" );
        },

Scripts, which are listed in the script menu, are more powerful & flexible since they can use shell scripts, AppleScript, Perl, Ruby, or any other scripting language.

Since I’m working with CFPlugin bundles, I need to deal with UUIDs. In most cases, you would use CFUUIDGetConstantUUIDWithBytes to specify a UUID, which requires a list of byte values. The shell command ‘uuidgen’ returns a string, so converting it for use with CFUUIDGetConstantUUIDWithBytes involves some tedious editing. With a script, you can simply insert the properly formatted UUID byte values.

Here’s my ‘Insert UUID as bytes’ script:

#! /usr/bin/perl -w
my $re = "\(..\)\(..\)\(..\)\(..\)-\(..\)\(..\)-\(..\)\(..\)-\(..\)\(..\)-\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\n";
my $uuid = `uuidgen`;

my $bytes = $uuid;
$bytes =~ s/$re/0x$1, 0x$2, 0x$3, 0x$4, 0x$5, 0x$6, 0x$7, 0x$8, 0x$9, 0x$10, 0x$11, 0x$13, 0x$14, 0x$15, 0x$16/;

print "// UUID: ".$uuid;
print "CFUUIDGetConstantUUIDWithBytes(NULL, ".$bytes.")";

I’m sure there’s a more elegant way to do it in a single line of Perl 🙂