June 24, 2009

Stars, man. Stars.

This reminds me of my favorite final exam question from University. Paraphrased: Trace the calcium in your teeth from the big bang to the end of the universe. I took some cool classes.

June 23, 2009

He's baaaaaack

Daniel Lyons appears to have resurrected fake Steve. Perhaps it's the new liver, maybe it's the new book. Either way... He's back, bitches.

February 24, 2009

Useful bash foo with subversion

I've been a command-line user of subversion (svn) for some time and have long enjoyed these little bits of bash foo.

Stripping .svn directories

I often start one-off little test projects in my private slush svn repository and then move them into their own repository for further development as (or if) they grow up. Sometimes you'll want to get rid of svn's footprints in a working directory.
rm -rfv `find . -name *\.svn`
The find . -name *\.svn finds all of the .svn folders that svn uses to track the repository and with the help of those handy back-tics, rm -rv does the recursive removal of svn tracking directories.

Adding new files

During that early "making lots of new stuff" phase, I often generate quite a number of files that need to be added to svn at once. This is one of those times where having (say) class files in their own subdirectory is nice. Running this command will svn add every file that isn't currently being tracked by svn in the current directory.
svn add `svn stat |grep \? |awk '{print $2}'`
Grep finds every svn stat output line that includes a question mark (meaning the item is not currently under version control) and pipes it through awk '{print $2}', which shows only the text (the filename) from the second column of the svn stat output. The back-tics and svn add finish the magic.

Using a Mulligan

I'll use something similar to the above along with svn revert to rollback a working copy "all the way." Say you're experimenting in your working directory; you've added a few files, hit a dead end, and want to revert the whole tree as well as delete anything you've added. In other words, you're looking for a full-on "do over." Using svn revert --recursive will revert any files that svn is tracking, but will leave anything svn is not tracking alone, so we have to also remove those files.
svn revert --recursive && rm -rf `svn stat |grep \? |awk '{print $2}'`

As with any other nerd foo, make sure that you really want to do what you're asking for when you use these commands. These make my life with svn just a little easier.

February 19, 2009

Brain clarity through body hacking and distractions

or... how I make my brain work more gooder*.

I've been known to fight foggy brain from time to time. You know what I mean? That decidedly uncool feeling of "can't do crap, too tired and dumb" that only seems to creep in when the to do list is longer than my ... um ... arm. Lately, though that feeling has struck me less and less often and I think I know why. I've lately zeroed - in on the right set of habits for me. Every now and again, I'll pick one of the topics below and write a short post expanding the topic. For now, though, just a list of things that work for me.

Continue reading "Brain clarity through body hacking and distractions" »

January 03, 2009

iPhone responsiveness and memory usage

I recently answered a question on a private mailing list about how to make a network - based (XML parsing and such) iPhone application more responsive. I've been encouraged to post it here by a few folks (Thanks, guys! You know who you are.). So, I figure "why not?" Here you go. (Slightly modified)

The original question (paraphrased): I have an iPhone application that downloads XML data from the web, parses it, and loads it all into memory. I notice that my app is a little sluggish and that it crashes as odd times, probably due to having too much information in memory. There are other apps that do this kind of thing on the app store and I notice that many of them are more responsive than mine. How does one make one's "network cloud-based" app more responsive?

My Answer

You're running into a few of the more common problems with embedded programming. Here are a few little tricks that have helped me in general (done a little embedded Linux programming, too) and on the iPhone.

Regarding bandwith / data size / responsiveness as a result of downloading data

You'll be surprised that the actual downloading of anything but pretty large amounts of data is pretty fast by itself. The part that is slow is the stuff that happens before the download even starts. Edge / 3G latency sucks and even DNS lookup is really really really (really?) slow on the iPhone in almost all circumstances AFAICT. I've found that strategies that download more data at a time while discarding unneeded data that you're getting on the fly, rather than making multiple requests for specific small chunks of data has been a performance win. That's a little counter intuitive.

Regarding memory

There is a reason the NSXMLDocument doesn't exist on the iPhone. You can get away with throwing a smallish XML tree into memory and go ahead and do it if it simplifies your life for small data sets, but the combination of larger XML trees in memory and whatever else (including UI) you have cached in memory can cause you to hit the memory ceiling at weird times; that's probably what's happening when your app crashes. The app will get terminated if you don't release memory when you get these memory warnings. Take a look at apples "Books" SQLite example. They're not doing exactly what you're looking for there (no network code), but the handling of memory works as they're doing it. They load data from a SQLite database lazily, but keep that data in memory until the application closes, until the owning object is deallocated, or when memory gets scarce. When the app gets those fun memory warnings, they save any changed data and release everything that they can get back out of the database later. This is similar in theory to the lazy loading of views we've all grown accustomed to (and that is partly handled for you). When a view controller gets a memory warning, its views are released by default if they don't have a superview, which is why you have to figure out if the view is still there every time you (re)load it. Doing something similar with your XML data by saving it somewhere when you get a memory warning and releasing the associated data structure, reloading it piecemeal from disk as needed (be it an SQLite database or what-have-you) works pretty well and appears to be the recommended approach. Ultimately, figuring out how much and which data to put on "disk" and/or in memory (and when) is the biggest PITA in embedded programming, but it's also the place where you're going to get the responsiveness you're looking for. http://furbo.org/2008/08/27/dealing-with-memory-loss-the-cleanup/

Regarding UI responsiveness

Don't use a lot of subviews and avoid opacity. Instead draw the views yourself... Draw once, if possible. ( http://blog.atebits.com/2008/12/fast-scrolling-in-tweetie-with-uitableview/ )

Other tricks

Use Instruments and Shark with the code running ON THE DEVICE to see how much memory you're using, how much disk access you're doing, and what is actually going on timing-wise. Optimize those specific areas profiling the simulator (faster edit, compile, test cycle). Rinse (on the device) and repeat.

Put breakpoints in memory warning methods and figure out when (and why) it's happening (again, on the device). Is it when you download data, load view A, then view B? Can you release view A's data when it goes off the screen to keep the memory footprint from growing? Do you need the whole tree for view B? Can you download it all, dump to disk, and load lazily? Blah blah blah. This stuff can get tricky, but try the obvious things first. Find out what is causing the memory ceiling problem and you're well on your way. :)

Using the LLVM/Clang static analyzer has saved me a lot of headaches as well. It's easy to forget that you have a web view somewhere with a bunch of cached data floating off screen causing the device to go bork bork...

Cache yesterday's data, load, and display it before going out to the network for today's data. Use a progress indicator and some other UI indicator to let the user know that you're updating from the network and that they're looking at what may be old data. Do this asynchronously. When it comes to displaying data from the network, sometimes you have to fake it 'til you make it. You don't have to rewrite Google gears or anything, just throw everything you need from the server onto disk and reload it when the app launches.

Gus Mueller's FMDB rocks for SQLite work. I have a version with embedded Dtrace probes if anybody wants it. (This will have to be the subject of a later article after I find some time to update my version to Gus' latest version and to send it to him to look at / integrate if he wishes first...)

December 04, 2008

Enumerating and visualizing all fonts on iPhone

When you're designing custom views or otherwise theming your iPhone application, it's nice to be able to see all of the available fonts. I couldn't find anything online that showed them, so I made my own little application. You can get it at FontListViz.tgz.



Screenshot 2008.12.04 01.27.59.jpg



It's pretty well dirt simple. Get all font family names, then get all of the font names in each family and store them in an array, then put each font name's text in a table view cell and set the table view cell's font using -[UIFont fontWithName:size:] and, well, Bob's your uncle -- instant very simple font viewer.

- (void)viewDidLoad 
{
    [super viewDidLoad];
    self.fontNames = [NSMutableArray array];
    NSArray *fontFamilyNames = [UIFont familyNames];
    for (NSString *familyName in fontFamilyNames) {
        NSLog(@"familyName = %@", familyName);
        NSArray *names = [UIFont fontNamesForFamilyName:familyName];
        NSLog(@"FontNames = %@", fontNames);
        [self.fontNames addObjectsFromArray:names];
    }
}
.
.
.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    
    static NSString *CellIdentifier = @"Cell";
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }
    
    NSString *name = [self.fontNames objectAtIndex:indexPath.row];
    cell.text = name;
    cell.font = [UIFont fontWithName:name size:14];
    return cell;
}

Microsoft Office Formats won't load on the iPhone simulator

Just an FYI:

The UIWebView in the simulator remains blank when loading MS office formats like word (.doc), excel (.xls), powerpoint (.ppt) (and possibly iWork formats as well -- Go Go Gadget Google indexer), but it does work on the device itself. Caveat coder. Don't pull your hair out for too long wondering why your files don't show up on the simulator. They will once you compile and install on the phone.
    NSString *filePath = @"pathToAnExcelDocument.xls";
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath] == YES) 
    {
        NSLog(@"Loading %@", filePath);
        NSURL *pathURL = [NSURL fileURLWithPath:filePath];
        //Warning: this doesn't load into the view on the simulator
        NSURLRequest *pathURLRequest = [NSURLRequest requestWithURL:pathURL];
        [someWebView loadRequest:pathURLRequest];
    }
radar://6417654