Adding a custom font to an Xcode project for Mac OS

I needed to add a custom font to a project today and had real trouble finding how to do it. There were lots and lots of iOS tutorials, with this being the best of them. But I was doing a Mac OS app, not an iOS app, and so the tutorial didn’t quite fit my needs.

In the end, a coworker helped me figure out what I was doing wrong. So here’s a quick set of steps, based on the Code with Chris link above.

  1. Include the fonts in your Xcode project.
  2. Make sure they’re included in the target you’re building.
  3. Double-check that they’re being copied as resources into the product bundle.
  4. Include the folder with your fonts in the app Plist. On Mac OS you need to use ATSApplicationFontsPath instead of UIAppFonts. Important: Don’t think you can leave this out just because your fonts aren’t in a subfolder! Even if they’re loose in Resources, you need to supply a path. Just use “.” in that case.
  5. Find the name of the font. On OS X, you can use this line:

    NSLog(@"%@",[[NSFontManager sharedFontManager] availableFontFamilies]);
  6. Use NSFont and NSAttributedString to create a string using the font:

    NSFont *font = [NSFont fontWithName:@"MyFont" size:20.0];
    NSDictionary *attributes = @{NSFontAttributeName : font};
    NSAttributedString *attString = [[NSAttributedString alloc] initWithString:@"But a virgin Wurlitzer heart never once had a song" attributes:attributes];

Changing CWD while using subprocess convenience methods

Today I wanted to call a subprocess and get its output. Something like this:

arguments = ['git', 'log', '-1', '--pretty=format:"%ct"', self.path]
timestamp = check_output(arguments)

This worked great when I was staying in the source tree of a single git project. However, as soon as I asked git to get the log of a file outside the current source tree, it returned nothing. Clearly, I needed to change the CWD first.

In looking at the docs, I found a cwd argument on Popen, but not check_output. But this helpful post suggested that I could still pass the cwd argument because check_output and friends use Popen underneath. And it works! Thanks to Shrikant for the tip. So the final code looks like this:

arguments = ['git', 'log', '-1', '--pretty=format:"%ct"', os.path.basename(self.path)]
timestamp = check_output(arguments, cwd=os.path.dirname(self.path))

Using Python’s FileList class

Recently I was looking for a Python class that would let me easily store and manipulate a list of file paths. I pretty quickly found distutils.filelist, which sounded like exactly what I needed, so I read the docs… and came away with no clear understanding of how to actually USE the class. Furthermore, Googling turned up nothing either.

The good news is that the class is quite compact. (You can find the source here.) And since it’s so simple, I was quickly able to work out how to use it. The key thing to know is that there are two variables: allfiles and files. The first contains everything, and you fill it up either using findall() or set_allfiles(). Once you have some files in allfiles, you can include them in the reduced list of files via include_pattern(). After you’ve selected some items, just read the files property.

If instead you only want to remove files/paths matching a pattern, you can put items into files directly and then cull the ones you don’t want with exclude_pattern(). Of course, you can also combine the two methods.

So this is the FileList example that the docs should contain, but don’t:

import distutils.filelist as fl

fileList = fl.FileList()
fileList.findall() # By default, uses CWD
fileList.include_pattern('*.xib', anchor=False)

print fileList.files

This will recursively look through all the files in the current directory and pull out the .xibs. What if the files aren’t on disk, but instead have come from a zip file? No problem:

import distutils.filelist as fl

fileList = fl.FileList()
zipfile = ZipFile(StringIO(someZipData))

fileList.extend(zipfile.namelist()) # Extends 'files', not 'allfiles'
fileList.exclude_pattern('__MACOSX/*') # Ignore OS X attribute directories
fileList.exclude_pattern('', prefix='.') # Ignore hidden files

print fileList.files

I hope these examples save you some time!

Sort lines by length and then alphabet in Xcode

I admit it, I’m a stickler for pretty code. One thing that offends my sense of aesthetics is when the #import block at the top of a .m file is all ragged. Much better to have them sorted by line length. But what about comments? And shouldn’t lines of the same length be sorted alphabetically?

I had a script to do this in Xcode 3, but then Xcode 4 came along and did away with scripts. But that’s because there’s now a way to do it with Automator. Follow these instructions:

http://stackoverflow.com/questions/8103971/sort-lines-in-selection-for-xcode-4

And then set the Shell to /usr/bin/perl and put this code in the Automator “Run Shell Script” action:

my @l;

my $chomped = 0;

sub trim {
	($trimmed, @drop) = split(q-//-, $_[0]);
	$trimmed =~ s/\s+$//;
	return $trimmed;
}

while (<>) {
	$l[$.] = $_;
}

# Remove the last line if it's just a newline
if (length($l[$#l]) == 1) {
	$chomped = 1;
	pop(@l);
}

@sorted = sort { length trim($a) <=> length trim($b) or lc($a) cmp lc($b) } @l;

print @sorted;

if ($chomped) {
	print "\n";
}

Finally, visit  > System Preferences… > Keyboard > Keyboard Shortcuts > Services and assign your new service a shortcut. (I chose Cmd-Opt-Ctrl-S.) And away you go.