Q: I have a class that I have made into a palette and I want to include it in several other palettes, either as itself or in conjunction with a subclass. Yet, when I try to load two palettes that contain my class, the second one produces a load error in InterfaceBuilder. If I only include the code for my class in the first palette, the second palette loads, but only if the first palette has been previously loaded (this is unacceptable!). How can I have this class exist in multiple palettes?
A: The problem is that palettes, like bundles, keep all of your classes in one object file inside of the palette file package. When the system tries to dynamically link this object file into an application (in this case InterfaceBuilder), it fails if it runs across any previously defined symbols (this is the case for classes that are linked into several different palettes). Failure to load the object file is not a fatal error. However, even though the multiply defined object in your palette may already linked into your application (say from a previously loaded palette) there were probably other classes that weren't loaded (ie, a subclass).
The solution is to try to load any classes that may exist in other palettes separately. You can do this by adding a new bundle subproject to your palette project (choose New Subproject... from the Project menu item, then set the type to Bundle from the pop-up list). Add your class (with any support classes, like its inspector) to this bundle project. You also have to add a new bundle subproject for any classes that depend on that class (i.e., subclasses). Finally, you need to add the following code to your subclass of IBPalette (which is created for you automatically when you create a new palette project) to load the (now separate) pieces:
@implementation MyPalette : IBPalette
- init
{
char path[MAXPATHLEN]; // Buffer to store path to bundles
// Do super init
[super init];
// Get path for bundle suproject called "MyClass"
[[NXBundle bundleForClass:[self class]] getPath:path
forResource:"MyClass" ofType:"bundle"];
// Create NXBundle for "MyClass" and load its object file. Ignore return
// value (assume that failure means class was already loaded).
[[[NXBundle alloc] initForDirectory:path] principalClass];
// Get path for bundle subproject called "MySubclassOfMyClass"
[[NXBundle bundleForClass:[self class]] getPath:path
forResource:"MySubclassOfMyClass" ofType:"bundle"];
// Create NXBundle for "MySubclassOfMyClass" and load its object file
if(![[[NXBundle alloc] initForDirectory:path] principalClass])
NXRunAlertPanel("MySubclassOfMyClass Load Error",
"Now something else went wrong!", "OK", NULL, NULL);
return self;
}
@end
QA887
Valid for 3.0, 3.1