Mac

AlphaBaby 3.0.3 Released

A new version of AlphaBaby for Mac, which fixes the bug causing some persistent crashes, has been released in the App Store. Download it today!

Major New Version of Mac AlphaBaby

I am excited to announce the newest version of AlphaBaby for MacOS. This is a major new version of AlphaBaby, and it adds many great features from the IOS version of AlphaBaby. You can now record your own voice for letters, shapes, numbers, and photos, right from inside of AlphaBaby. You can create configurable sets of options. Maybe one day you want to work on letters and numbers, and other day look at photos of family members. With the Sets feature of AlphaBaby, it is easy to switch between different set of options. You can even share sets created on the iOS version of AlphaBaby with the Mac version, or send your Mac sets to your iOS devices.

Perhaps the most important new feature is one that has been requested for years -- the ability to completely block the keys at the top row of the keyboard, including volume and brightness! Your computer is more protected than ever when running AlphaBaby!

Try out AlphaBaby 3.0 today! It’s available exclusively in the Mac App Store for only $.99 USD.

Global variables vs method calls

During my rewrite of Mac AlphaBaby, I’ve been trying to do things the “right way”. That has meant a lot of restructuring of code, trying to reuse classes where possible, and general consolidation. I’ve learned a lot since I first started writing Mac AlphaBaby back in 2003 and I want to bring the code base up to more modern standards.

One of the things I’ve often wondered about in Objective-C is the cost for doing things the “right” way. Every time I make 3 method calls (at least!) for something that might have been a single structure access or global variable access in a C program of yesteryear, I cringe a bit. I know that computers have gotten so much faster that it doesn’t really matter how many virtual or dynamic method calls I’m making for something that isn’t in a speed critical path. However, the part of me that learned C and debugged embedded programs in assembly to optimize for speed still didn’t feel great about all that extravagant method calling.

The current case in question is when creating a string whose value needs to be created a runtime, but then is constant after that, is better off being accessed via a global variable or by some kind of method call on a class. Here’s my test class, with all different ways to access a string:

//  Globaler.h
#import <Foundation/Foundation.h>

extern NSString *globalString;

@interface Globaler : NSObject
{
    NSString    *myInstanceString;
    NSString    *propertyString;
}

@property (nonatomic, retain) NSString *propertyString;

+ (NSString *)staticString;
+ (Globaler *)sharedGlobaler;
- (NSString *)instanceString;

@end

static NSString    *myStaticString;

NSString *globalString;

@implementation Globaler

@synthesize propertyString;

+ (void)initialize
{
    myStaticString = [NSString stringWithFormat:@"Hello %@ world",
            @"static"];
    [myStaticString retain];
    globalString = [NSString stringWithFormat:@"Hello %@ world",
        @"global"];
    [globalString retain];
}

+ (NSString *)staticString
{
    return myStaticString;
}

+ (Globaler *)sharedGlobaler
{
    static Globaler    *theGlobaler = nil;
    if (theGlobaler == nil) {
        theGlobaler = [[Globaler alloc] init];
    }
    return theGlobaler;
}

- (NSString *)instanceString
{
    return myInstanceString;
}

- (id)init
{
    self = [super init];
    if (self != nil) {
        myInstanceString = [NSString stringWithFormat:@"Hello %@ world",
            @"instance"];
        [myInstanceString retain];
        self.propertyString = [NSString stringWithFormat:@"Hello %@ world",
            @"property"];
    }
    return self;
}

@end

And here’s the code which accesses the strings in different ways:

NSString    *refString = @"reference string";

- (void)dealloc
{
    [super dealloc];
}

#define NUM_ITERS    100000000

- (BOOL)doStuffWithString:(NSString *)str
{
    if (str == refString) {
        return YES;
    }
    return NO;
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
    NSString     *str;
    Globaler    *g;
    NSTimeInterval    tStart, tEnd;
    int    i;
    
    g = [Globaler sharedGlobaler];
    tStart = [NSDate timeIntervalSinceReferenceDate];
    for (i = 0; i < NUM_ITERS; i++) {
        str = globalString;
        if ([self doStuffWithString:str]) {
            break;
        }
    }
    tEnd = [NSDate timeIntervalSinceReferenceDate];
    NSLog(@"global variable time: %f: %f", tEnd - tStart,
        ((tEnd - tStart) / (NUM_ITERS * 1.0) * 1000.0));
    
    tStart = [NSDate timeIntervalSinceReferenceDate];
    for (i = 0; i < NUM_ITERS; i++) {
        str = [Globaler staticString];
        if ([self doStuffWithString:str]) {
            break;
        }
    }
    tEnd = [NSDate timeIntervalSinceReferenceDate];
    NSLog(@"static variable time: %f", tEnd - tStart);
    

    tStart = [NSDate timeIntervalSinceReferenceDate];
    for (i = 0; i < NUM_ITERS; i++) {
        str = [g instanceString];
        if ([self doStuffWithString:str]) {
            break;
        }
    }
    tEnd = [NSDate timeIntervalSinceReferenceDate];
    NSLog(@"instance variable time: %f", tEnd - tStart);

    tStart = [NSDate timeIntervalSinceReferenceDate];
    for (i = 0; i < NUM_ITERS; i++) {
        str = g.propertyString;
        if ([self doStuffWithString:str]) {
            break;
        }
    }
    tEnd = [NSDate timeIntervalSinceReferenceDate];
    NSLog(@"property variable time: %f", tEnd - tStart);

    tStart = [NSDate timeIntervalSinceReferenceDate];
    for (i = 0; i < NUM_ITERS; i++) {
        str = [Globaler sharedGlobaler].propertyString;
        if ([self doStuffWithString:str]) {
            break;
        }
    }
    tEnd = [NSDate timeIntervalSinceReferenceDate];
    NSLog(@"shared property variable time: %f", tEnd - tStart);

}

What did I find? About what I expected to find. The raw global variable access is the fastest, and it pretty much gets slower as you go on down the line. But, calling a static function which returns a pre-computed static variable came in second. This has some advantages: a relatively small amount of characters to type, you can initialize the static string in the +(void)initialize method, so it only gets created when needed, and it can be put into a more general utility-type class, which lets you group such variables into named collections (named by the class they are in). Here are the timing results:

global variable time: 0.695643
static variable time: 1.075534
instance variable time: 1.268580
property variable time: 1.128956
shared property variable time: 1.496929

The most expensive way to call - using a static method to get a global shared object, whose property we then access, is about twice as slow as the raw global variable. But, the static variable is at least a little closer, and seems just as clean. Bottom line, I had to bump up the iteration count pretty high to even get these numbers (measured in seconds), so all of this stuff is just ridiculously fast, and I probably don’t have to worry about it. But, the low-level tech geek person in me just wanted to know, and it will help me make some design choices (and avoid bad ones for the sake of nonexistent performance concerns).

Snowtober wrecked my Inbox

I had been doing so well with the Inbox. Keeping it under control. Responding quickly to messages.

Then Snowtober hit. Four days without power (and therefore without magic Inbox cleaning) has reduced me back to 447 messages, 251 unread. Mostly this is because I was still checking mail on my phone, but was unable to file it there. And since I use POP instead of IMAP for accessing my mail accounts, I basically have to deal with the same messages all over again. I’m sure msgFiler will once again be a huge help, but all I can say is “Curse you, Snowtober!”

Load Images quickly in Mail

Msgfiler is still doing wonderful things for my Inbox. However, once I was so efficient and keyboard-based for all of my filing needs, the one place that still required a mouse was more obvious: clicking the “Load Images” button for a HTML email message with remote images. By default, I have “load remote images” turned off, but there is the occasional message where I would like to load them. A Google search turned up similar questions, but no real solutions.

So today, I tried my hand at a bit of Applescript programming, and was able to solve it! This is for Mail on Lion - it may require some tweaking on earlier versions of Mac OS X. It also requires that you have “Enable access for assistive devices” turned on in the “Universal Access” preference pane. The script uses the UI Scripting ability of Mac OS X, which lets you target individual UI elements. So, as long as Apple doesn’t move or rename the “Load Images” button, this script should continue to work, no matter the size or location of your Mail window. I trigger it from Butler, but you could save the Applescript as an executable, and then run it from Spotlight, or have it triggered from your LauncherOfChoice. It’s quick and easy and one less reason to use the mouse!

Hope this helps someone else!

tell application "System Events"
    tell process "Mail"
        tell UI element 1 of row 1 of table 1 of scroll area 1 of splitter group 1 of splitter group 1 of window 1
            tell button "Load Images"
                click
            end tell
        end tell
    end tell
end tell

Mail orgainzation update

Quick update: After purchasing MsgFiler yesterday, I have filed 5609 messages! Wow. My Inbox is now officially clean and ready for business. If anyone has any AlphaBaby or BabyProof features or suggestions to send me, I can assure you I will most definitely see them, and reply quickly! :)

One tip for using MsgFiler, which I found in their support section, but not in the documentation, is that you can delete a message while in MsgFiler by using command-shift-delete. Definitely a must-have key combo when doing a major clean-out.

How should I organize my mail?

I’ve been investigating add-ons for Apple’s Mail.app, looking for ways to help me better organize my Inbox. I keep coming down to a basic question: use tags or folders to organize messages? Then I discovered this paper from the University of Washington. Bottom line - they did a whole study, and their answer is still - “it depends”. So, in my grand quest to be better organized, it looks like I’ll be purchasing both MailTags and MsgFiler. Mail ActOn is intriguing too - might not rule out a triple purchase!

I’ll start out with MsgFiler, and see if I can truly make a difference in my Inbox with a bit more diligent filing.

(In looking for the link to the first paper, I discovered another paper from IBM Research on a similar subject. Who knew that email organization was a hot research topic?)

Removing old Time Machine backups

Here’s a quick note about removing old Time Machine backups, in case you ever run into a similar situation.

I had moved my Time Machine backups to a new, larger drive. However, I left the old backup on the original drive, and had added files to that drive. So, I couldn’t just reformat the old drive to wipe out the Time Machine backup file. Dragging it to the trash, and then emptying the trash didn’t work - it sat there for hours computing > 3 millions of files to be delete before I finally gave up and stopped it.

A few Google searches later, here’s what finally worked for me:

Drag the old, unwanted Backups.backupdb folder to the Trash. In a Terminal window, cd to the root of the volume where the folder used to live. Use the Unix rm command to delete the backup, as root:

cd /Volumes/OldDrive
sudo rm -rf .Trashes/501/Backups.backupdb

This took almost a day, and seemed to hang overnight, so I restarted it, but it did successfully delete the entire backup.

In the future, I’ll definitely make sure I use Disk Utility to erase any disk that has an old Time Machine backup on it, instead of trying to remove it myself!