Cocoaphony

Pandora's "Profile" Pop-up

Several people have noted that PandoraBoy is displaying a “Profile” window over the player that interferes with the player. This is a notification from Pandora because they’ve changed their privacy settings (you can now make your profile private, and they want to know if you want that).

This should be a one-time event for existing accounts. I suspect that new accounts will not see it. The solution is to open www.pandora.com in Safari, answer the question, and then re-launch PB.

PandoraBoy goes directly to the the mini-player on launch. Pandora doesn’t code for that since it’s impossible from the website. So sometimes they make interfaces that are larger than the mini-player without updating the mini-player code to resize. PB doesn’t resize the window (it doesn’t know how large it should be). It just relies on the mini-player to do it in Javascript, but in cases like this, the mini-player also doesn’t know how large the window should be.

BTW, I often am asked why PB doesn’t make the window resizable for cases like this. The answer is that it doesn’t help. The mini-player is a flash app, and has a clipping frame independent of the window. So while you can resize the window, the content is still clipped at the border of the flash app. Ah, the wonders of Flash.

PandoraBoy 0.8.2 - Fixes Flash

For those of you having trouble with Flash 10.1, I’ve fixed PB to handle it. This moves from the hackish “dig around in the NetscapePlugin objects and call undocumented methods” approach to a standard CGEvent based keyboard injection. You can’t use NSApp’s sendEvent: to talk to Flash (probably because Flash is not in Cocoa). But the following code is a good general purpose “send me a virtual keystroke.”

Building Address Book Plugins

Just a reminder, because the template doesn’t seem to set this up correctly. To build an Address Book action plugin for 10.6, you need to compile for x86_64 or it will silently not show up. If you plan to support 10.5, you’ll need i386 as well. The template seems to build 32-bit universal (i386, ppc) by default.

Hijacking With method_exchangeImplementations()

Based on a discussion from StackOverflow.

Sometimes you want to inject some logic into a method you don’t control. The most common sane reason to do this is for debugging or profiling. For instance, you might want to log every time the various NSNotificationCenter methods are called so you can determine if that’s a performance bottleneck. (As I discovered myself, if you have thousands of notification observations in your system, it can be a serious performance problem.)

In most OOP languages your only option would be to subclass the object you want to instrument and then arrange for every instance of that object to be your subclass. In many cases that’s either very difficult or outright impossible, particularly if the object is used internally by a system framework. But Objective-C is highly dynamic, and message dispatching is resolved at runtime. You can modify how it works.

Wrapping C++ - Take 2, Part 1

Last year, I presented an approach to wrapping C++. Since then, I’ve been introduced to other approaches, particularly from gf who helped me better understand opaque objects. Since I do a lot of cross-language work, I’ve had some opportunity to play with and expand this, and so I’d like to update my C++ wrapping approach.

First, to remind everyone of the problem: you have a C++ object that you want to consume in Objective-C. That’s easy in ObjC++, but if you make an ivar that references a C++ class, then the header file can only be included by ObjC++ classes. This quickly spreads .mm files throughout your project, creating all kinds of headaches. ObjC is a beautiful thing, and C++ is fine, but ObjC++ is a crazy land that should be carefully segregated from civilized code. So how do we do it?

Chinese Study

Over the years I’ve travelled to China several times, and now I’m working with large group of developers in Suzhou, Hangzhou and Hefei. A few weeks ago I was able to visit again, and that’s gotten me back in the mood to study Chinese. It often helps me to write down things as I learn them, and some of my Chinese coworkers read this blog and might help set me straight as I wander through their language like a bull in a China shop (as it were….) It’s a bit off the trail for Cocoa development, so feel free to use the Subscribe2 link on the right to take this category off of your email subscription.

NSLog Ain't Printf in -Wformat

So say you had this code:

printf("%s", 1);
NSLog(@"%s", 1);

And you compiled with -Wformat. You might expect both of these lines to kick out a warning:

Format '%s' expects type 'char *', but argument 2 has type 'int'

You’d be particularly misled when you went and looked at the definition of NSLog():

FOUNDATION_EXPORT void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));

Why look there, doesn’t that look like it should provide format type checking? Oh how foolish. Neither gcc nor clang can actually handle that __NSString__ specifier in a robust way. So the first line above will give a useful warning, but the second one will silently compile and later crash. Exciting, I know. You have been warned.

-Wformat-nonliteral and -Wformat-security do catch dangerous calls like NSLog(foo), so __NSString__ isn’t a complete loss, but it’s a shame we can’t get type checking here.

There’s a good discussion of this at NSLog(…) improper format specifier affects other variables?

iPhone as a Career

Prashant P. wrote me recently asking some questions that I thought I’d answer here. First, can iPhone development be full time job, and second, will it help him get into a “mainstream job” in Java, .NET, etc. As he notes, most of the iPhone development he’s seen has been a part-time rather than full-time job; a side-line rather than a career.