Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/NativeScript/GlobalObject.mm
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,10 @@ static void runLoopBeforeWaitingPerformWork(CFRunLoopObserverRef observer, CFRun
Class firstBaseWithMeta = klass;
while (!meta) {
firstBaseWithMeta = class_getSuperclass(firstBaseWithMeta);
if (!firstBaseWithMeta) {
// Treat unknown root classes (which don't inherit from NSObject) as `NSObject`
firstBaseWithMeta = [NSObject class];
}
meta = MetaFile::instance()->globalTableNativeInterfaces()->findInterfaceMeta(class_getName(firstBaseWithMeta));
}

Expand Down
24 changes: 13 additions & 11 deletions src/NativeScript/ObjC/ObjCTypes.mm
Original file line number Diff line number Diff line change
Expand Up @@ -121,20 +121,22 @@ JSValue toValue(ExecState* execState, id object, Class fallbackClass, const Meta
return jsNull();
}

if ([object isKindOfClass:[NSString class]] && fallbackClass != [NSMutableString class]) {
return jsString(execState, (CFStringRef)object);
}
if (class_getInstanceMethod(object_getClass(object), @selector(isKindOfClass:))) {
if ([object isKindOfClass:[NSString class]] && fallbackClass != [NSMutableString class]) {
return jsString(execState, (CFStringRef)object);
}

if ([object isKindOfClass:[@YES class]]) {
return jsBoolean([object boolValue]);
}
if ([object isKindOfClass:[@YES class]]) {
return jsBoolean([object boolValue]);
}

if ([object isKindOfClass:[NSNumber class]] && ![object isKindOfClass:[NSDecimalNumber class]]) {
return jsNumber([object doubleValue]);
}
if ([object isKindOfClass:[NSNumber class]] && ![object isKindOfClass:[NSDecimalNumber class]]) {
return jsNumber([object doubleValue]);
}

if ([object isKindOfClass:[NSDate class]]) {
return DateInstance::create(execState->vm(), execState->lexicalGlobalObject()->dateStructure(), [object timeIntervalSince1970] * 1000.0);
if ([object isKindOfClass:[NSDate class]]) {
return DateInstance::create(execState->vm(), execState->lexicalGlobalObject()->dateStructure(), [object timeIntervalSince1970] * 1000.0);
}
}

GlobalObject* globalObject = jsCast<GlobalObject*>(execState->lexicalGlobalObject());
Expand Down
9 changes: 9 additions & 0 deletions tests/TestFixtures/Interfaces/TNSInheritance.m
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,12 @@ + (TNSIBaseInterface*)instanceFromUnrelatedPrivateType {

@implementation TNSBlacklistedInterface
@end

OBJC_ROOT_CLASS
@interface TNSPrivateRootClass

@end

@implementation TNSPrivateRootClass

@end
6 changes: 6 additions & 0 deletions tests/TestRunner/app/Inheritance/InheritanceTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2209,6 +2209,12 @@ describe(module.id, function () {

expect(TNSGetOutput()).toBe(expected);
});

it("Private root class is accessible from JS", function(){
const privateClass = objc_getClass("TNSPrivateRootClass");
expect(privateClass).toBeDefined();
expect(privateClass.__constructorDescription).toBe("Known class: NSObject Unknown class: TNSPrivateRootClass");
});

describe("instanceof", function () {
it("TNSIBaseProtocolImpl_Private returned as TNSIBaseInterface*", function () {
Expand Down