Vincent Gable

July 5, 2008

FourCharCode2NSString

Filed under: MacOSX, Objective-C, Programming, Sample Code, Usability — Tags: , , , — Vincent Gable @ 8:13 pm

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().

-dealloc Warning

Filed under: Bug Bite, Cocoa, MacOSX, Objective-C, Programming — Tags: — Vincent Gable @ 8:06 pm

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 — Tags: , , — Vincent Gable @ 1:20 am

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

NSApplicationName Inconsistencies

Filed under: Bug Bite, Cocoa, MacOSX, Objective-C, Programming, Sample Code — Tags: — Vincent Gable @ 7:06 pm

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.

Learning From Other People’s Failures: Acrobat Reader 9

Filed under: MacOSX, Usability — Tags: , , — Vincent Gable @ 5:58 pm

Epic Fail.

The PC version is awful too.

June 20, 2008

Modern Browsers

Filed under: MacOSX, Programming, Quotes — Tags: , — Vincent Gable @ 12:12 pm

… 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

June 17, 2008

Every OS Sucks

Filed under: MacOSX, Programming, Usability — Tags: — Vincent Gable @ 8:35 am

Funny, and true, video.

June 16, 2008

Hold off on Upgrading QuickTime to Version 7.5

Filed under: Announcement, MacOSX, Tips — Tags: — Vincent Gable @ 2:12 pm

The QuickTime 7.5 update appears to have broken sound in VMWare Fusion, and also in some code I’m working on. I will know more once I have fixed the issue in my own code. But for now, I advise waiting to update QuickTime to version 7.5.

June 3, 2008

AppleScript is the Uncanny Valley

Filed under: Design, MacOSX, Programming, Quotes, Usability — Tags: , , , — Vincent Gable @ 11:39 pm

A interesting theory:

I think this “like English but not quite” aspect of AppleScript is the Uncanny Valley of programming languages. Because AppleScript looks like English it is easy to fall into the trap of believing it has the flexibility of English. When that mental model fails its more unsettling than when you screw up the syntax in a regular programming language because your mental model isn’t making unwarranted assumptions.

Mark Reid

May 31, 2008

Messages to Nowhere

Filed under: Bug Bite, Cocoa, MacOSX, Objective-C, Programming — Vincent Gable @ 5:14 pm

If you send a message to (call a method of) an object that is nil (NULL) in Objective-C, nothing happens, and the result of the message is nil (aka 0, aka 0.0, aka NO aka false). At least most of the time. There is an important exception if sizeof(return_type) > sizeof(void*); then the return-value is undefined under PowerPC, and thus all Macs for the next several years. So watch out if you are using a return value that is a struct, double, long double, or long long.

The fully story:

In Objective-C, it is valid to send a message to a nil object. The Objective-C runtime assumes that the return value of a message sent to a nil object is nil, as long as the message returns an object or any integer scalar of size less than or equal to sizeof(void*).
On Intel-based Macintosh computers, messages to a nil object always return 0.0 for methods whose return type is float, double, long double, or long long. Methods whose return value is a struct, as defined by the Mac OS X ABI Function Call Guide to be returned in registers, will return 0.0 for every field in the data structure. Other struct data types will not be filled with zeros. This is also true under Rosetta. On PowerPC Macintosh computers, the behavior is undefined.

I was recently bitten by this exceptional behavior. I was using an NSRange struct describing a substring; but the string was nil, so the substring was garbage. But only on a PPC machine! Even running under Rosetta wouldn’t have reproduced the bug on my MacBook Pro. Undefined values can be a hard bug to detect, because it may have reasonable values in it when the test is run.

A few simple guidelines can help you avoid my misfortune:

• Be especially careful using of any objective-C method that returns a double, struct, or long long

• Don’t write methods that return a double, struct, orlong long. Return an object instead of a struct; an NSNumber* or float instead of a double or long long. If you must return a dangerous data type, then see if you can avoid it. There really isn’t a good reason to return a struct, except for efficiency. And when micro-optimizations like that matter, it makes more sense to write that procedure in straight-C, which avoids the overhead of Objective-C message-passing, and solves the undefined-return-value problem.

• But if you absolutely must return a dangerous data type, then return it in a parameter.
Bad:
- (double) crazyMath;
Good:
- (void) crazyMathResult:(double*)result;.

I love Objective-C’s “nil messaging” behavior, even though it is rough around the edges. It’s usefulness is beyond the scope of this article, but it can simplify your code if you don’t return a data-type that is larger then sizeof(void*). With time, when the intel-style return behavior can be universally relied on, things will be even better.

Newer Posts »

Powered by WordPress