Main

September 26, 2010

My 2 cents in (hopefully) 5 minutes

saggau_speakerbadge.png

I'm performing a 5 minute "lightning" talk at the iPad/iPhone DevCon tomorrow and I'm not planning to use slides. I don't want to burn half of the 5 minutes getting keynote working, but hopefully attendees would like to have some of the links and code I'll reference. So! Here are my notes, links, and other such fodder. There is a lot more than 5 minutes worth of material here as I've been making notes about my habits for the last week or so; this is all of them. I plan to talk until I run out of air or out of time...

Tiny Little Habits for the iOS Dev to Avoid Premature Baldness

A foolish consistency is the hobgoblin of little minds, adored by little statesmen and philosophers and divines.
-- R.W. Emerson (Essays. First Series. Self-Reliance.)

Here are some consistencies that I think are not foolish. These little habits have saved me a lot of stupid, often difficult to debug, mistakes.

When you alloc and init or otherwise instantiate an object that you now own, write the balancing release or autorelease immediately; this includes any IBOutlets and properties. If it's an IBOutlet, also write the [self setSomeIBOutletProperty:nil] in -viewDidUnload when you write the [someIBOutlet release] in -dealloc.

Similarly

When something that is a delegate of something else, in the dealloc I'll tend to perform [somethingElse setDelegate:nil], whether I expect somethingElse to live for a while longer or not, then [somethingElse release]; on the next line. When you write [somethingElse setDelegate:something], write this code right away just like the alloc+init discipline above. This is one of the reasons I don't like to set delegates in xib files. It's too easy to mess this up. Also, I refactor as I work...

Speaking of delegates and protocols

When you write a delegate protocol, make absolutely every method optional so you get into the habit of testing if the delegate responds to the selector you're about to call as a matter of course. You're a lot less likely to mess up the delegate protocol that way. When you conform to a protocol, copy all (required and optional) methods into your class and comment them out. Uncomment them as you need to use them. That way, you don't have to go back and forth to the other class's header file to see if there is a delegate method for some behavior you need to know about. You have it all at hand.

Do as little setup work as possible in xibs, they work best for simply putting together UI geometry

  • Avoid xib file dependencies (See this BNR blog post) Avoid making view controllers in MainWindow.xib
    • It's easy enough to make 'em in code. It's easier to know where things come from when you make them in code.
  • Avoid setting delegates in xib files. Do it in code.
I'm not saying not to use xibs, they're useful and they often save time; I am saying to keep the interface builder voodoo to a minimum.

Lines of code are (mostly) free

Self-documenting code is better than heavily commented code and Objc is verbose by tradition; I think this is a good thing. Debugging code that isn't too nested is much easier.
[self setFloozle:[floozaWhat whatWithString:[NSString stringWithFormat:@"jeeminy %@ Christmas, %@", frickin, virginiaName]];
Where you gonna put a breakpoint in that crap?

When you think you can draw something in code instead of using a static image, try to find the time to implement drawing it in code. Also, Buy Opacity.app.
  • When apple comes out with yet another screen size, you'll be (somewhat more) ready for it.
  • When you want to change the size of something for some other reason, you don't have to generate a new image.
  • You get to figure out how on the green Earth you designer does the crazy things they do in photoshop... only in Quartz.

Speed

If the profiler doesn't say it's slow, it's not slow. If the profiler says it's slow, it's slow. Use the profiler.
Note: Shark (sniffle) is dead. Long live Shark! They killt it good in iOS 4.0 (no longer runs on the device).

Others' little code bits that are very useful:
  • Red Sweater NSData thing that prints the hex for you
  • IsEmpty from Wil Shipley with a small addition
    static inline BOOL IsEmpty(id thing) {
        return thing == nil
        || ([thing isEqual:[NSNull null]]) //My addition for things like coredata
        || ([thing respondsToSelector:@selector(length)]
            && [(NSData *)thing length] == 0)
        || ([thing respondsToSelector:@selector(count)]
            && [(NSArray *)thing count] == 0);
    }
    
  • LogMethod() from Aaron Hillegass
    //Modified from Aaron hillegass's code
    #define LogMethod() NSLog(@"-[%@ %s]", self, _cmd)
    
  • CPU and Memory tools I use to see what's really going on that I know I stole from a skojillian places, but can't remember who to thank.
  • GTMHTTPFetcher to download stuff (and Google Toolbox for Mac in general)
  • Nathan Eror's Core Animation Toys.

Subclassin' -- You stay classy, San Diego

Subclass less, compose more. In subclasses, always call super's implementation of a method, even when you just *know* it does nothing. (I'm thinking of UIViewControllers here). That way, if you ever do decide to put in an intermediary class between your class and the former superclass, you don't get stuck wondering what happened when those methods no longer get called.

Minimize direct access to the internals of your objects

Yeah, yeah, message send blah blah. It's not that slow unless you abuse it.
  • Write or synthesize accessors for ivars you want to share. Also, buy Accessorizer.app
  • Remember, you can use readonly in a property when appropriate (and it is more often appropriate than you might think).
  • Mark ivars you don't want messed with as @private. For srsly.
  • Make good use of class continuations:
    • to document the internal workings of your objects (If the header is the public documentation, the continuation is the private, implementation documentation)
    • to suppress "may not respond to" compiler warnings
    • to expand readonly properties to readwrite status internally
    • to make a protected methods header file if you want subclasses, but not other users of a class, to use certain of its internal methods.
      • Import that file in subclasses to suppress compiler warnings.
      • Makes it easy to delineate private vs. protected vs. public methods

Know what you're really doing when you use dot syntax

I have a weird dot syntax habit, ymmv. There be message sends in them thar hills.

I rarely return nil from something that is expected to return a string, dictionary, an array, or a set

Instead, I return an empty object of the expected type like so:
    return @"";
    return [NSArray array];
    return [NSDictionary dictionary];
I often use Shipley's IsEmpty() to find out if some object is empty, rather than comparing its pointer to nil. That way, nil messaging returning nil doesn't bite you in the ass when you're expecting something that is not an NSObject and you don't get that ugly (null) string in your UI. I hate that.

Make a logging method you can turn off and one you really can't; both call through to NSLog

Also, see the expansion of LogMethod from Aaron Hillegass
#define LogMethod() SBLog(@"-[%@ %s]", self, _cmd)
#define WarnMethod() SBWarn(@"-[%@ %s]", self, _cmd)
#define SBWarn NSLog

#ifdef DEBUG
#define SBLog NSLog
#else
#define SBLog    
#endif

Run the static analyzer, but not all the time

I usually run it:
  • before a commit to source control
  • after I make a new class
  • any time I am alloc'ing a lot of stuff
However, I don't find it particularly useful to set the preference that will run it for every compile; For me, the time spent on that adds up quickly. I have a lot of fairly big projects,though. YMMV.

If your code won't work unless some particular condition is satisfied, NSAssert that condition!

(Hi Joe P.) You can turn off asserts in shipping code, if you're a panzy. I leave 'em on. I would rather get a crashing bug I can reproduce than one I can't and it's probably gonna crash soon enough...

NO WARNINGS (and turn on the warning set you can find on the blog the Rentzsch linked to that one time)

On External, third party, projects

  • READ THE CODE
  • UNDERSTAND THE CODE
  • DON'T USE IT UNTIL YOU KNOW HOW IT WORKS (make a little test project to learn it and drop lots of breakpoints)
  • If it's hard to read, it's probably broken.
  • I'm on the three20 mailing list; you wouldn't believe some of the questions asked there...
  • Add external files project relative outside of your project (makes updating the external project easier)
  • Freeze external projects at a given revision number; update early on between releases:
    • in svn this is done with gtmOauth -r 19 http://gtm-oauth.googlecode.com/svn/trunk in an svn:external
  • Avoid editing external projects directly (makes it hard to merge), instead subclass or make categories to change behavior
  • When possible, avoid static libraries
    • Too many places where compiler flags are set.
    • Instead, compile in only those parts you need and their dependencies
    • I usually add just the top level source file I need and pull in dependencies as the compiler pukes, rinse and repeat until no errors or warnings.

Make tiny little test projects for new features

  • As your codebase grows, new features can present a difficult integration, so split it into two steps
    • 1. New Feature
    • 2. Integrate new feature into codebase
    • 3. goto 1

If there is any chance that you've got a delayed perform of a selector scheduled, don't forget to cancel those when appropriate

+[NSObject cancelPreviousPerformRequestsWithTarget:]
+[NSObject cancelPreviousPerformRequestsWithTarget:selector:object:]
Incolsolata, because menlo makes left square brackets look indented.

If you have to pick just one: Read Mike Ash's blog.

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" »

December 09, 2007

Always - on Print Preview

Some software is, in my experience, not quite WYSIWYG when it comes to the final printed output so I have gotten into the habit of viewing a PDF in preview before I actually send a document to my printer. This has saved many trees.

Apple makes it fairly easy to do this. Just command-P and click on the weird-looking PDF button to get the drop down menu to select "Open PDF In Preview."

preview.jpg

I would like to see most every print job automatically open in preview without needing to take my hands off of the keyboard. One can make this happen with a little bit of effort, some help from Folder Actions, and a little piece of free third-party software. Here's how I do it.

First, download and install Cups PDF per the instructions on its home page. This will create a printer and driver that dumps a pdf file into ~/Desktop/cups-pdf/. Set your default printer to CUPS-PDF.

Next, you will setup a folder action on the ~/Desktop/cups-pdf/ to open each file that gets dumped in there in preview. I keep my folder actions scripts in ~/Desktop/Folder\ Actions/, so I put the following applescript (derived from a similar script that ships with Leopard) there.

  
(*
add - new item alert

This Folder Action handler is triggered whenever items are added to the attached folder.
The script will display an alert containing the number of items added and offering the user
the option to reveal the added items in Finder.

Copyright © 2002–2007 Apple Inc.

You may incorporate this Apple sample code into your program(s) without
restriction. This Apple sample code has been provided "AS IS" and the
responsibility for its operation is yours. You are not permitted to
redistribute this Apple sample code as "Apple sample code" after having
made changes. If you're going to redistribute the code, we require
that you make it clear that the code was descended from Apple sample
code, but that you've made changes.
*)

property dialog_timeout : 5 -- set the amount of time before dialogs auto-answer.

on adding folder items to this_folder after receiving added_items
try
tell application "Finder"
--get the name of the folder
set the folder_name to the name of this_folder
end tell

-- find out how many new items have been placed in the folder
set the item_count to the number of items in the added_items
--create the alert string
set alert_message to ("Folder Actions Alert:" & return & return) as Unicode text
if the item_count is greater than 1 then
set alert_message to alert_message & (the item_count as text) & " new items have "
else
set alert_message to alert_message & "One new item has "
end if
set alert_message to alert_message & "been placed in folder " & «data utxt201C» & the folder_name & «data utxt201D» & "."
set the alert_message to (the alert_message & return & return & "Would you like to view the added items?")

display dialog the alert_message buttons {"Yes", "No"} default button 1 with icon 1 giving up after dialog_timeout
set the user_choice to the button returned of the result

if user_choice is "Yes" then
tell application "Preview"
--fire it up
activate
--open the items
open the added_items
end tell
end if
end try
end adding folder items to

Ctrl (or right) click the cups-pdf folder, Enable Folder Actions, then Configure Folder Actions via the contextual menues seen below.


EnableFolderActions.jpg

When you select "Configure Folder Actions" you'll set the script that runs every time a new file is added to that folder to the one above.

folderActions.jpg


Now every time you hit command - P to print in a application, you'll hit enter to print to your default CUPS-PDF printer, which will write a PDF to the cups-pdf folder on your desktop. The folder action will then pop-up this window (for five seconds).

PreviewMe.jpg


All you have to do is hit enter.

So! Every time I print I hit command - P, enter, wait a sec, enter. Instant preview.

September 28, 2007

whaaa?

I've spent 2007 thinking it's 2008.

October 12, 2006

Geek wants his information!

runinfo.jpg

Apparently, when I'm a-runnin (er was runnin' back before I messed up mah hip), I like to know what's happenin...
and I pause a lot. It's because I'm a wimp. ok?

Little Icons:
? = Ask the nike+ for progress (how far, how fast)
! = Played the "powersong"
|| = pause workout (sometimes for stretching, mostly for going "can't breathe")

September 04, 2006

(Badass-mother-turtle) Feng shui

My little turtle friend has a big (compared to him) rock that he likes to sort of hide beneath. Unfortunately, the overhang the rock provides scares me; I fear he may oneday get himself stuck under there. So... I thought it might be a good idea to put some smaller, more rounded, rocks around the overhang of the big rock. Apparently "it's for your own good" isn't much of an explanation for a turtle. His unceasing (and somewhat noisy) project for the last several days has been a major "I want to hide under there" rock rearrangement. He takes breaks to eat, sleep, and occasionally stretch out under the UV lamp. Even as I write this he's treading water looking at me with a that's right, I'm a badass mother-turtle face. He deserves the moniker. Some of those rocks are almost as big as he is.

May 19, 2006

It's not in a box. anymore...

My family used to have a little joke we developed along with our habit of moving every few years. Every time we couldn't find something the answer was "it's in a box." I've been living here for a while, but something about my visit to the container store (a GREAT retail experience, by the way... better than the apple store) to buy a few of their exclusive-to-the-container-store white sterilite storage containers has cause an organize my house meltdown. Of course I ended up having a bunch of other organization tools delivered, thinking I would eventually start throwing stuff out to reorganize what had become a stack of white file-archiving boxes from Staples.

feng shui attack! (Yes, Jenny, I still have my Nintendo).

So here I am, happily scarfing a pop tart (you can get those delivered here in New York) looking out over the vast, comparitively desolate landscape that is my little home. I've spent the last four hours, already exhausted from a busy day, opening every box I had stored in closets and tossing old junk. I had no idea the extent to which I am a pack rat. I found the packaging for every piece of technology I have bought in the last three years, most of the corresponding techno-geekery, two years worth of magazines, too many random "to do" lists from grad school, and even the recovery disks for my very first laptop. (Toshiba Satellite, ca. 1997, P133, 32MB of RAM baby!)

And believe it or not my new macbook is resting on my bed. Earlier than expected. Unopened. Taunting me. I think it's too cool to come out until my home represents the proper environment for a computer that wears a tuxedo. My cluttered desk was ok for anodized aluminum, a RISC processor, and 1024x768 pixels. But this is flat-black (stay away from me with that spraypaint, Dad), *INTEL* (I don't need no reduced instruction set), and wide screen.

Now it's time to continue the tradition of taking a screwdriver or putty knife to my new computer before I even turn it on... time to add 2 GB of ram.

((Incoherence and probable misspellings not intentional, but I can't keep my eyes open. Now, where's my screwdriver set? I'm not going to be able to find anything for weeeeeks))

April 08, 2006

More coffee physics... or don't knock it 'til you try it.

You know you're a caffeine fiend when you make your morning oatmeal with hot coffee instead of water or milk.