Load userland NS classes from the main bundle as well as frameworks, and temporarily change the class of NSSwapper classes to the target class when calling KVC methods.

This commit is contained in:
Aparajita Fishman
2011-06-04 18:03:53 -07:00
parent a74267e937
commit 4be0bb3a30
3 changed files with 60 additions and 25 deletions
+6 -6
View File
@@ -40,12 +40,12 @@ ConverterConversionException = @"ConverterConversionException";
@implementation Converter : CPObject
{
CPString inputPath @accessors(readonly);
CPString outputPath @accessors;
CPString resourcesPath @accessors;
NibFormat format @accessors(readonly);
CPArray themes @accessors(readonly);
CPArray frameworkNSClasses @accessors;
CPString inputPath @accessors(readonly);
CPString outputPath @accessors;
CPString resourcesPath @accessors;
NibFormat format @accessors(readonly);
CPArray themes @accessors(readonly);
CPArray userNSClasses @accessors;
}
+ (Converter)sharedConverter
+29 -4
View File
@@ -39,10 +39,10 @@ var _CPCibClassSwapperClassNameKey = @"_CPCibClassSwapperClassNameKey",
if (!swapperClass)
{
// If this is a framework NS class, call its KVC methods directly
// If this is a userland NS class, call its KVC methods directly
var nsClass = nil;
if ([[[Converter sharedConverter] frameworkNSClasses] containsObject:aClassName])
if ([[[Converter sharedConverter] userNSClasses] containsObject:aClassName])
nsClass = objj_lookUpClass("NS_" + aClassName);
var originalClass = nsClass || objj_lookUpClass(anOriginalClassName);
@@ -51,9 +51,26 @@ var _CPCibClassSwapperClassNameKey = @"_CPCibClassSwapperClassNameKey",
objj_registerClassPair(swapperClass);
/*
When calling userland KVC methods, they should think that the class is
the NS class (not the swapper class) so that they are in their userland space,
not in AppKit space. For example, this ensures that bundleForClass:[self class] will work correctly.
We can accomplish this safely by changing the class of self temporarily and sending directly
to self instead of to super. This swizzle is safe because NSClassSwapper and _CPCibClassSwapper
do not add any ivars.
*/
class_addMethod(swapperClass, @selector(initWithCoder:), function(self, _cmd, aCoder)
{
self = objj_msgSendSuper({super_class:originalClass, receiver:self}, _cmd, aCoder);
if (nsClass)
{
// Switch to userland temporarily
self.isa = nsClass;
self = objj_msgSend(self, _cmd, aCoder);
self.isa = swapperClass;
}
else
self = objj_msgSendSuper({super_class:originalClass, receiver:self}, _cmd, aCoder);
if (self)
{
@@ -73,7 +90,15 @@ var _CPCibClassSwapperClassNameKey = @"_CPCibClassSwapperClassNameKey",
class_addMethod(swapperClass, @selector(encodeWithCoder:), function(self, _cmd, aCoder)
{
objj_msgSendSuper({super_class:originalClass, receiver:self}, _cmd, aCoder);
if (nsClass)
{
// Switch to userland temporarily
self.isa = nsClass;
objj_msgSend(self, _cmd, aCoder);
self.isa = swapperClass;
}
else
objj_msgSendSuper({super_class:originalClass, receiver:self}, _cmd, aCoder);
// If this is a custom NS class, lookup its archiver class so that
// the correct class is swapped during unarchiving.
+25 -15
View File
@@ -52,7 +52,7 @@ var FILE = require("file"),
CPString appDirectory;
CPString resourcesDirectory;
CPDictionary infoPlist;
CPArray frameworkNSClasses;
CPArray userNSClasses;
}
- (id)initWithArgs:(CPArray)theArgs
@@ -67,7 +67,7 @@ var FILE = require("file"),
appDirectory = @"";
resourcesDirectory = @"";
infoPlist = [CPDictionary dictionary];
frameworkNSClasses = [];
userNSClasses = [];
}
return self;
@@ -153,7 +153,8 @@ var FILE = require("file"),
var loadFrameworksCallback = function()
{
[converter setFrameworkNSClasses:frameworkNSClasses];
[self loadNSClassesFromBundle:[CPBundle mainBundle]];
[converter setUserNSClasses:userNSClasses];
[converter convert];
};
@@ -573,18 +574,7 @@ var FILE = require("file"),
[frameworkBundle loadWithDelegate:nil];
[self setLogLevel:verbosity];
// See if the framework defines NS classes
var nsClasses = [frameworkBundle objectForInfoDictionaryKey:@"IBClasses"] || [];
for (var i = 0; i < nsClasses.length; ++i)
{
var filename = "NS_" + nsClasses[i] + ".j";
objj_importFile(FILE.join(frameworkPath, filename), YES);
CPLog.debug("Imported framework NS class: %s", filename);
frameworkNSClasses.push(nsClasses[i]);
}
[self loadNSClassesFromBundle:frameworkBundle];
}
finally
{
@@ -597,6 +587,26 @@ var FILE = require("file"),
aCallback();
}
- (void)loadNSClassesFromBundle:(CPBundle)aBundle
{
// See if the framework defines NS classes
var nsClasses = [aBundle objectForInfoDictionaryKey:@"IBClasses"] || [],
bundlePath = [aBundle bundlePath];
for (var i = 0; i < nsClasses.length; ++i)
{
if (userNSClasses.indexOf(nsClasses[i]) >= 0)
continue;
var path = FILE.join(bundlePath, "NS_" + nsClasses[i] + ".j");
objj_importFile(path, YES);
CPLog.debug("Imported NS class: %s", path);
userNSClasses.push(nsClasses[i]);
}
}
- (CPArray)getThemeList:(JSObject)options
{
var defaultTheme = options.defaultTheme;