Re: "weak link" framework refs for 10.1 compatibility?
Re: "weak link" framework refs for 10.1 compatibility?
- Subject: Re: "weak link" framework refs for 10.1 compatibility?
- From: Piers Uso Walter <email@hidden>
- Date: Sun, 10 Nov 2002 12:34:40 -0500
Dan Wood wrote:
I'm trying to add some AddressBook framework and NSAppleScript
functionality to my app, but still allow for 10.1 compatibility. I'm
making sure that no 10.2-specific methods get called in my code, and
that's straightforward, but what is a problem is the constants (e.g.
the Address Book constants in ABGlobals.h, or
NSAppleScriptErrorMessage) are declared within the frameworks, that
cause the bundle not to load in 10.1.
This is exactly what we wanted to do and we've come up with the
following solution.
We've isolated the address book functionality into two platform specific
bundles, one for 10.1 and one for 10.2. Each bundle is built using the
matching OS version and is linked against the address book framework of
that OS version. Both bundles have the same interface, so that the
application can use either one. The application ships with both bundles
and determines at run time which one to load, using the following method:
- (void)_loadAddressBundle
{
NSArray *addressBundleNames = [NSArray
arrayWithObjects:@"AddressBundle_10.2.bundle",
@"AddressBundle_10.1.bundle", nil];
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *bundlePath = [mainBundle bundlePath];
NSString *addressBundleBasePath = [NSString
stringWithFormat:@"%@/Contents/Resources", bundlePath];
int i, count;
NSBundle *addressBundle; // will be loaded from a
platform specific bundle
#if ! DEBUG
// We do not want to send bundle loading errors to /dev/null in
debug versions
int fd_devnull;
int fd_stderr;
int fd_stderr_new;
#endif // ! DEBUG
// Initially we used the NSAppKitVersionNumber in order to decide
which bundle version to load (NSAppKitVersionNumber < 645.3:
AddressBundle_10.1.bundle, NSAppKitVersionNumber >= 645.3:
AddressBundle_10.2.bundle). This works without any problems, but is not
very elegant from a conceptual standpoint. It is somewhat far-fetched to
use the AppKit framework version in order to deduce which address
framework may be present in a system.
// Our new approach tries to load an address bundle, starting with
the latest one and falling back to earlier versions, if necessary. Each
address bundle is linked against its matching address framework. If this
framework is not available, the bundle cannot be loaded (unfortunately,
NSBundle writes an error message to stderr in this case, which we have
to "remove"). By testing the results of the bundle loading operation, we
can determine the success, and decide to fall back to an earlier bundle
version, if necessary. This is a much cleaner solution because it
actually (implicilty) tests the version of the address framework.
#if ! DEBUG
fd_devnull = open("/dev/null", O_WRONLY, NULL); // this file
descriptor points to /dev/null
fd_stderr = dup(STDERR_FILENO); // this file
descriptor points to wherever stderr points to
#endif // ! DEBUG
count = [addressBundleNames count];
for (i = 0; i < count; i++) {
// Try loading an address bundle (going from newest to oldest
one):
NSString *addressBundleName = [addressBundleNames
objectAtIndex:i];
NSString *addressBundlePath = [[NSString
stringWithFormat:@"%@/%@", addressBundleBasePath, addressBundleName]
stringByResolvingSymlinksInPath];
addressBundle = [NSBundle bundleWithPath:addressBundlePath];
if (nil != addressBundle) {
// We've found a bundle.
#if ! DEBUG
// Temporarily redirect stderr to /dev/null (because
NSBundle writes an error message to stderr if a bundle can't be loaded
and we do not want to see this error message in non-debug versions):
fd_stderr_new = dup2(fd_devnull, STDERR_FILENO); // stderr now
points to /dev/null
#endif // ! DEBUG
// Try to load the bundle:
addressController = [[[addressBundle principalClass] alloc]
init];
#if ! DEBUG
// Restore stderr:
fd_stderr_new = dup2(fd_stderr, STDERR_FILENO); // stderr now
once again points to wherever it pointed to before
#endif // ! DEBUG
if (nil != addressController) {
break;
}
}
}
#if ! DEBUG
fd_stderr_new = close(fd_devnull);
fd_stderr_new = close(fd_stderr);
#endif // ! DEBUG
if (nil == addressController) {
ILRunLocalizedAlertPanel(@"No Local Address Book Title", @"No
Local Address Book Message", nil, nil, nil, addressBundleBasePath);
return;
}
} // -_loadAddressBundle
I hope this helps.
With kind regards
Piers Uso Walter <email@hidden>
ilink Kommunikationssysteme GmbH
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.