i’m so full of ideas

Archive for February, 2009

nibless

February 23, 2009 7:59 pm

Update: The linked blog post in this article that explains how to create a nibless Xcode project is now dead. Go read this post instead.

This might sound heretical, but here goes: I don’t like Interface Builder.

I used the 2.x versions to build this. I got along with it acceptably well at the time, I guess, although it was never my favorite program. Then Apple completely rewrote it from the ground up for 3.0, whenceforth it didst suck, yea verily.

My complaint is a simple one: Interface Builder is 87 billion times more complex than it should be. Dozens of windows, hundreds of tabs, thousands of buttons, sliders, text input fields, check boxes, outlets, hinges, beads, knobs, joints, pipes, and zippers. Every time I start it up, I dread the ordeal I know I’m in for. It takes me half an hour to find the one check box I need in a sea of extraneous crud. Once I get a view or window set up appropriately, the steps I went through to get there are not easily documented or remembered.

I know that laying out user interfaces and wiring up controls is a big job. I know that somebody must need all that crud I never use, or it wouldn’t be there. But couldn’t Apple use its legendary user interface skills to de-emphasize the infrequently-used parts? I’m dyin’ here.

If you’re writing a Mac/Cocoa app, I guess you’re stuck with it. You’ve probably got at least a few fairly complicated windows to manage, along with dozens of menu items. But if you’re writing an iPhone/UIKit app, the value proposition changes. iPhone apps tend to have only a handful of user interface objects and connections. In this scenario, Interface Builder’s weaknesses outweigh its strengths.

It’s easy to assume that it’s impossible to build an iPhone or Mac app without Interface Builder. As a matter of fact, I once spent several months figuring out how to build Cocoa apps without NIBs, because I was writing a cross-platform GUI framework, so obviously they had to go. It wasn’t easy, because it’s not done very often, but I succeeded. And the first version of the iPhone SDK didn’t even give you the opportunity to use Interface Builder, you were forced to create your user interface in code.

Now we reach the part of the blog entry where I should tell you how to make an iPhone app without NIBs. Alas, this gentleman has already done a far better job of it than I would have. So you can instead read what he wrote, secure in the knowledge that someone else produced a solution, while I produced a bunch of hot air and whining. You’re welcome.

I’m now working on the user interface for my first iPhone app. I have several views set up, all completely NIB-free. It’s far preferable to create a user interface element in 10 lines of code, rather than making yet another soul-destroying 20-minute slog through Interface Builder. I suppose it’s possible that I’ll run into some situation that forces me to reconsider, but at this point, I’m willing to go far, FAR out of my way to avoid having to invite that sad piece of software back into my life, thank you very much.

let me be your piggybank

February 5, 2009 11:16 am

For many years, I was the primary Allen Brunson on the internet. Searching for my name, roughly 18 of the top 20 hits were all me me me.

Fast forward to the present. The internet is now mainstream. A much larger percentage of the populace has some sort of presence here. It turns out that there are a lot more Allen Brunsons than I would have thought.

Some time in late 2008, the Facebook page for some other Allen Brunson became the number one hit for our shared name. I’m not proud of it, but I have to admit, I was miffed. I’ve spent decades using computers, generating shareware projects and comment threads and zine articles and websites and so on, but this kid gets the top spot? Hrrmph.

Lately I’ve been making more of an effort to advertise. This blog is proof of that. It might be working? As of this writing, I’ve moved above the Facebook guy.

For posterity, here’s the top ten google hits for today:

1) Generic page at LinkedIn for all Allen Brunsons. They must be doing well these days.

2) My résumé on this website.

3) The rival Allen Brunson on Facebook. I also have a page there, but not many friends, so my Facebook page doesn’t appear anywhere in the top 50 hits.

4) My author page at actionscript.org, for the lone Flash article I wrote.

5) My profile page at BeBits. I haven’t logged into that in years.

6) A letter to the editor I wrote on Salon. I wish this one would sink a little lower.

7) A page at classmates.com for an Allen Brunson that went to high school in Mobile, Alabama.

8) A page at pipl.com that’s generically for all Allen Brunsons everywhere, apparently. A few of the details there are from me, but most aren’t. It’s like they made a composite of all Allen Brunsons? A tad disturbing.

9) Another generic page at reunion.com that is again for all Allen Brunsons. I see the guy from Mobile on there, but not me.

10) My page at FriendFeed. I got flattered into signing up, but I hardly ever use it.

I guess I’m thinking about this right now because I’m attempting to make the transition from boring corporate jobs to interesting contracting and startup work. People that are doing what I want to do all have ubiquitous online presences, establishing strong reputations. Sorry, all you other Allen Brunsons, for hogging so many of the top spots, but I need the exposure. Heh!

bash: timing long-running processes

February 3, 2009 1:44 pm

The innertubes have spoken. According to the search terms I’m seeing in my access logs, you interwebbernauts want to see more bash articles. Very well, then.

Every now and then I write a bash script that might take an hour or more to run. It’s nice to know exactly how long it took, so you can plan accordingly when you want to run it the next time. So I formalized some bash timing concepts I’ve been using for years and packaged them up into a code library you can use in your own scripts.

If you’re just interested in the code, you can skip to the bottom of this entry and cut-and-paste the parts you want into locations of your choosing. If you’ve got a minute, I’ll explain some of the non-obvious bits.

bash functions can only return small integers, typically not larger than 255 or so. They are intended for use as values you’d return to the shell, when the script is finished running. If you want to write a function that returns a string or a large integer, you’re out of luck. The way I get around that one is to write functions that use echo to print a string to stdout. The output can be captured by a calling function using this rather awkward syntax:

    returnValue=$(functionName)

Unfortunately, variables in bash scripts are by default global, and therefore available to all functions. I don’t like that very much, so my local variable declarations are all prefixed with the keyword local, which is supposed to make them visible only within the current function. I have a sneaking suspicion that supposedly local variables can still “leak” into other functions, however. I suppose I should investigate that situation and use it as the basis for a future blog post.

Finally, you can use the source keyword to pull functions from one script into another, like this:

    source timerlib.sh

Now, on to the code. First up is timerlibtest.sh, a script that demonstrates use of the timerlib functions.

#!/bin/sh # timerlibtest.sh -- test for timerlib.sh # by allen brunson  allen.brunson@gmail.com  february 3 2009 # pull in timerlib functions source timerlib.sh # this function shows how to time a long-running process function main() {     # save current time at the beginning     local time=$(timerStart)         # put whatever you want to time here     echo "starting long-running process ..."     sleep 2         # display how long it took     timerStop $time "elapsed time:" } # execution start main $*

Here is the text for timerlib.sh:

#!/bin/sh # timerlib.sh -- functions for timing long-running operations # by allen brunson  allen.brunson@gmail.com  february 3 2009 # return seconds since 1970 # does not work on some unix variants.  check 'man date' for details function timerCurrent() {     date "+%s" } # inputs a number of seconds, outputs a string like "2 minutes, 1 second" # $1: number of seconds function timerLengthString() {     local days=$((0))     local hour=$((0))     local mins=$((0))     local secs=$1     local text=""         # convert seconds to days, hours, etc     days=$((secs / 86400))     secs=$((secs % 86400))     hour=$((secs / 3600))     secs=$((secs % 3600))     mins=$((secs / 60))     secs=$((secs % 60))         # build full string from unit strings     text="$text$(timerLengthStringPart $days "day")"     text="$text$(timerLengthStringPart $hour "hour")"     text="$text$(timerLengthStringPart $mins "minute")"     text="$text$(timerLengthStringPart $secs "second")"         # trim leading and trailing whitespace     text=${text## }     text=${text%% }         # special case for zero seconds     if [ "$text" == "" ]; then         text="0 seconds"     fi         # echo output for the caller     echo ${text} } # formats a time unit into a string # $1: integer count of units: 0, 6, etc # $2: unit name: "hour", "minute", etc function timerLengthStringPart() {     local unit=$1     local name=$2         if [ $unit -ge 2 ]; then         echo " ${unit} ${name}s"     elif [ $unit -ge 1 ]; then         echo " ${unit} ${name}"     else         echo ""         fi     } # useful for testing timerLengthString function timerLengthStringTest() {     local days=$((86400))     local hour=$((3600))     local mins=$((60))     local secs=$((1))         timerLengthString  0     timerLengthString 20     timerLengthString $(( ($hour * 3) + ($mins * 1) + ($secs * 52) ))     timerLengthString $(( ($days * 1) + ($secs * 14) )) } # synonym for timerCurrent function timerStart() {     timerCurrent $* } # display final elapsed time # $1: value returned from an earlier call to timerStart() # $2: optional descriptive string, such as "total wait time:" function timerStop() {     local desc=$2     local secs=$((0))     local stop=$(timerCurrent)     local text=""     local time=$1         if [ "$desc" != "" ]; then         text="$desc "     fi         secs=$(( $stop - $time ))     text="$text$(timerLengthString $secs)"         echo $text }

more meta

February 2, 2009 9:44 pm

At the time of this writing, one of my entries is the second google hit for “ideas bash scripts unix” and “complex bash scripts”. According to my access logs, a couple of people have found me that way. Cool!

Unfortunately, the spammers also found me, in record time. So I’ve currently got comments pretty thoroughly locked down. I think I’ve allowed people who have created accounts here to comment, and nobody else.

I’m not trying to discourage discussion, I just don’t like having to clear the crud out of my blog two or three times a day. Until I get the hang of this, you are encouraged to email me at the address on my “About” page.