Vincent Gable’s Blog

July 5, 2008

FourCharCode2NSString

Filed under: MacOSX,Objective-C,Programming,Sample Code,Usability | , , ,
― Vincent Gable on July 5, 2008

As I have written before, the best way to convert a FourCharCode to an NSString* for NSLog()ing is to use the NSFileTypeForHFSTypeCode() function. But for the life of me I can’t remember that name, even though I use it about once a month. It’s too long, and it has too little to do with what I’m using it for.

So I have added the line:
#define FourCharCode2NSString(err) NSFileTypeForHFSTypeCode(err)
To my prefix-files, because I can remember FourCharCode2NSString().

UPDATE: (2008-08-06) There is an even easier way.

-dealloc Warning

Filed under: Bug Bite,Cocoa,MacOSX,Objective-C,Programming |
― Vincent Gable on July 5, 2008

The only time you should call ever call -dealloc in Objective-C is on the last line of your own -dealloc method. This call should be [super dealloc];. The proper way to dispose of an object is to send it a -release message — -dealloc will then be called if appropriate.

Now when I was first learning Cocoa, I sometimes disposed of objects by calling -dealloc directly. This caused all sorts of problems. Truth be known, if I’ve been messing with several object’s -dealloc methods, I’ll sometimes dyslex out and type dealloc when I mean release, just because it’s more fresh in my head. This is very rare, but it has happened once, and will happen again. I’m fallible like that. Murphy’s law tells us that I won’t catch it every time.

So I humbly propose that GCC should warn you if you use -dealloc any way other then calling [super dealloc]; on the last line of your own -dealloc methods.

Missing Frameworks

Filed under: Bug Bite,Cocoa,MacOSX,Objective-C,Programming | , ,
― Vincent Gable on July 5, 2008

I tried using an AMWorkflowView in a project, but when I ran it, I would crash with the following printed to the console:


*** Terminating app due to uncaught exception ‘NSInvalidUnarchiveOperationException’, reason: ‘*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (AMWorkflowView)’

It turns out I just forgot to include Automator.framework in my project!

It turns out that you also have to include Automator.framework to use any OSAScriptView objects.

I hope this helps someone who googles the error message :-).

July 3, 2008

NP-Complete is Often Easy

Filed under: Design,Programming,Quotes | , , ,
― Vincent Gable on July 3, 2008

There are a lot of problems that are, in theory, incredibly difficult – but because the difficult cases are very rare and rather contrived, they’re actually very easy to solve. Two examples of this that I find particularly interesting are both NP complete. Type checking in Haskell is one of them: in fact, the general type inference in Haskell is worse that NP complete: the type validation is NP-complete; type inference is NP-hard. But on real code, it’s effectively approximately linear. The other one is a logic problem called 3-SAT. I once attended a great talk by a guy named Daniel Jackson, talking about a formal specification language he’d designed called Alloy. Alloy reduces its specification checking to 3-SAT. Dan explained this saying: “The bad news is, analyzing Alloy specifications is 3-SAT, so it’s exponential and NP-complete. But the good news is that analyzing Alloy specifications is 3-SAT, so we can solve it really quickly

Mark Chu-Carroll (aka MarkCC

NSApplicationName Inconsistencies

Filed under: Bug Bite,Cocoa,MacOSX,Objective-C,Programming,Sample Code | , , ,
― Vincent Gable on July 3, 2008

The value stored under the NSApplicationName key of the result of [[NSWorkspace sharedWorkspace] activeApplication] is not the always the name the user knows the application by. Worse, it’s not always the same as the name for the application that other APIs expect or return. Even fullPathForApplication: in NSWorkspace sometimes won’t recognize it!

The problem stems from the fact that there are at least five application names floating around, at least in concept: (1) the file name the Finder sees, which in the case of an application package is the package (bundle) name; (2) the name of the executable inside the package, (3) the long name used in many places for display purposes only; (4) the short name used as the application menu title and in a few other places where a long name won’t fit for display purposes; and (5) the process name of a running application. They aren’t always the same, especially in Microsoft and Adobe products.

–From an informative message by Bill Cheeseman.

So instead of relying on NSApplicationName I now use -[[NSFileManager defaultManager] displayNameAtPath:] then strip off the filename extension. This should give exactly the filename the user sees. Every time.


NSDictionary *appInfo = [[NSWorkspace sharedWorkspace] activeApplication];
NSString *appPath = [appInfo objectForKey:@"NSApplicationPath"];
NSString *name = [[[NSFileManager defaultManager] displayNameAtPath:appPath] stringByDeletingPathExtension];

And of course, you really should be using bundle identifiers, instead of names, to identify an application. Unfortunately, a very few applications are not bundles. (For example, Microsoft stuff prior to Office 2008), so it might be necessary to fall back on using a name to locate them in a path-independent way.

Creating a custom CFBundleName in an application’s info.plist file seems to confuse NSApplicationName. For this reason I don’t think setting it is a good idea.

UPDATE 2010-01-20: See also, Technical Q&A QA1544: Obtaining the localized application name in Cocoa

June 20, 2008

Modern Browsers

Filed under: MacOSX,Programming,Quotes | , , , ,
― Vincent Gable on June 20, 2008

… What struck me watching these (WebKit) demos is that you could build a really slick web app UI using stuff like the canvas tag, SVG, and advanced CSS. Yes, none of this stuff works in IE, and IE still has massive market share — but not among the sort of people who adopt hip new web apps. The combined market share for, say, Firefox 3 and Safari 3 is larger than the overall market share for Mac OS X. Plenty of developers write desktop software that only works on the Mac — why aren’t more people writing apps web apps that only work in truly modern web browsers? The first one to do it is going to be a sensation.

John Grubber

I didn’t have a sense for how far behind IE lags, historically and today, until I saw this compatibility table (via Toby Jungen),

Calculation of support of currently displayed feature lists

Internet Explorer Firefox Safari Chrome Opera
Far Past 6.0: 4% 2.0: 34% 3.1: 43% 0.2: 54% 9.0: 35%
Past 7.0: 12% 2.0: 34% 3.1: 43% 0.2: 54% 9.0: 35%
Present 8.0: 29% 3.0: 48% 3.2: 67% 1.0: 54% 9.6: 58%
Near Future (2009) 8.0: 29% 3.5: 78% 4.0: 88% 2.0: 84% 10.0: 63%
Future (2010 or later) 9.0: 29% 4.0: 86% 4.*: 88% 2.0: 84% 10.*: 72%

June 17, 2008

Every OS Sucks

Filed under: MacOSX,Programming,Usability |
― Vincent Gable on June 17, 2008

Funny, and true, video.

June 11, 2008

Bring an Extra Battery for WWDC

Filed under: Programming,Tips | , ,
― Vincent Gable on June 11, 2008

I was chatting with a saleswoman at the San Francisco Apple Store, a few blocks from where WWDC is being held this year. According to her, the top things people wearing WWDC badges bought from the Apple Store are (most popular to least popular):

Laptop Batteries. Specifically, 15″ MacBook Pro batteries. This is apparently #1 by a wide margin. It’s what I was in the store to buy. I don’t normally carry a brick spare battery with me, because in my experience you can’t rely on it being charged when you need it. But at WWDC, there are stations which charge your battery while you work, so you always have a fresh battery ready to swap in. You can go the whole day without plugging in!

Power Adapters. (I guess battery chargers are not a panacea)

Laptop bags/backpacks. This one is funny, because Apple gave out a laptop case to every WWDC attendant. I’ve always thought that giving out laptop carriers to people at a tech conference was a bad idea, because everyone there already has a laptop and a laptop carrier that fits them. Mass-produced swag is probably not going to be better quality then something a nerd picked out for their computer. More people purchased a backpack then a smaller brief-case-sized carrier (presumably so they could haul around extra gear).

So when you go to WWDC, bring an extra battery. It’s the number-one thing attendees (including me) regretted not bringing so much that they ran out to buy one.

June 6, 2008

case:

Filed under: Bug Bite,C++,Cocoa,Design,Objective-C,Programming
― Vincent Gable on June 6, 2008

This bug was frustrating enough that half-way through squashing it, I promised myself I would document the solution. Unfortunately, it’s not a particularly interesting bug, but a promise is a promise!

I had some code very much like:

typedef enum {NoError, ReadError, WriteError, NetworkError, UnknownError} ErrorType;
...
void DescriptionOfError(ErrorType err, char *string)
{
   switch(err)
   {
      IOError:
         strcpy(string, "Could not read data.");
         break;
      
      WriteError:
         strcpy(string, "Could not write data!");
         break;

      NetworkError:
         strcpy(string, "Network Error. Make sure you have an internet connection and try again");
         break;
      
      NoError:
         strcpy(string, "No error.");
         break;

      default:      
      UnknownError:
         strcpy(string, "Unknown error.");
         break;
   }
}

int main (int argc, char** argv)
{
   char desc[1024];
   DescriptionOfError(ReadError,desc);
   printf("error: %s\n", desc);
   return 0;
}

And it just wouldn’t do the right thing, but for the life of me I couldn’t see what was wrong.

The “solution” was very simple, and somewhat embarrassing. I forgot the case keyword before the labels in the switch statement. Turns out that if you don’t have a case in-front of a label, it’s treated like a goto label, not a switch label. And this is something that I’ve known for years, but for 20 minutes I kept reading the code, and my brain would interpret what it should say, not literally analyze it.

This was extremely frustrating, not because it took me a long time to fix (I wish all my bugs could be squashed in just 20 minutes!), but because the results I was seeing totally violated my mental model of what should have happened. Violating someone’s mental model is more unsettling then you might imagine — avoid doing it at all costs.

My First Octal Value

Filed under: Bug Bite,C++,Cocoa,Objective-C,Programming | , , ,
― Vincent Gable on June 6, 2008

Octal is useless today. It is easy to convert between octal and binary, so octal was used in some early computers. But hexadecimal has totally replaced it in modern use. There’s no advantage that octal has over hexadecimal, which is why hexadecimal has replaced it.

The C programming language has support for values in octal. This wouldn’t be a problem, except for the horrible syntax used to define octal values.

In C, any integral value that starts with 0 is interpreted as octal! So 010 is eight, not ten. I’ve been bitten by this before. I don’t know why this syntax was chosen over an 0o prefix (which google calculator uses), that would match the 0x prefix for defining hexadecimal values. In retrospect it was almost certainly a mistake to go with the current syntax.

Anyway, the reason I’m writing this is because for the first time ever, I used an octal value in a C program. I had to create a directory structure that could be be accessed by different accounts on the same system. So I had to explicitly set it’s permissions when I created it with createDirectoryAtPath:attributes: . I wanted the NSFilePosixPermissions value that determines the folders permissions to have the same format that the chmod command takes. And it takes an octal value. So 0777 is the first, and only, octal constant that I’ve written in any program. Even when I’ve written in assembly I’ve used hexadecimal. There’s a good chance I will never write another octal value — I hope that’s the case.

« Newer PostsOlder Posts »

Powered by WordPress