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.”
Read more…
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.
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.
Read more…
In the last post, we discussed how to wrap simple C++ objects in Objective-C. But how about more complex objects, particularly with shared_ptr? Read more…
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?
Read more…
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?
From a StackOverflow posting.
When I teach Cocoa, I always ask the class what their background is in. This generally tells me what they need to unlearn before they’re ready for Cocoa. Here are some of the things I’ve found that different groups need to unlearn. Read more…
Now that we’re past the New Year, and I have a chance to reorganize my schedule, I’m working up my next series of postings. While you’re all patiently waiting, go read gotoAndPlay. I started out helping Geri on some layer drawing questions on StackOverflow, and have really gotten interested in his efforts to make his apps really beautiful.
PandoraBoy’s user interface is pretty screwed up since the recent Pandora update. I’ve talked with Pandora and it’s a known problem with WebKit. You’ll see the same issues if you run Safari. Pandora is working on a fix, and when they deploy it, PandoraBoy should automatically work again.
NSCopying is not always as simple to implement as you would think. Apple has a good write-up discussing the complexities, but let me elaborate. Forgive some ranting digressions. It’s important to know how to work around the problems I’m going to discuss, but it’s also important to understand how insane it is to have to work around this issue.
First, there’s the fairly obvious problem of deep versus shallow copies. If object foo has an instance variable *bar, should a copy of foo have a second pointer to bar, or should it have its own copy of whatever bar points to? There is no way to answer this question generally; it depends on the nature of the objects.
Most of the time, this can be dealt with fairly easily by implementing the accessors with the correct behavior (retain versus copy), and you wind up with a copyWithZone: like this:
- (id)copyWithZone:(NSZone *)zone
{
Product *copy = [[[self class] allocWithZone: zone] init];
[copy setProductName:[self productName]];
return copy;
}
That works really well as long as your superclass doesn’t implement NSCopying, but if it does, you may not have enough information or access to cleanly copy it. Now you would think this would be easy:
- (id)copyWithZone:(NSZone *)zone
{
Product *copy = [super copy];
[copy setProductName:[self productName]];
return copy;
}
But that may or may not work. If super implements -copyWithZone: as described above, then all is fine. But what if your superclass uses NSCopyObject()? Things go badly, and in ways very difficult to understand and debug. Read more…