Stop requiring to inherit NSObject when passing Swift object to Kotlin
This commit is contained in:
committed by
GitHub
parent
2d882d1b6c
commit
8d1ef86270
@@ -239,9 +239,6 @@ val nsNumber = 42 as NSNumber
|
||||
|
||||
Kotlin classes and interfaces can be subclassed by Swift/Objective-C classes
|
||||
and protocols.
|
||||
Currently a class that adopts the Kotlin protocol should inherit `NSObject`
|
||||
(either directly or indirectly). Note that all Kotlin classes do inherit `NSObject`,
|
||||
so a Swift/Objective-C subclass of Kotlin class can adopt the Kotlin protocol.
|
||||
|
||||
### Subclassing Swift/Objective-C classes and protocols from Kotlin
|
||||
|
||||
|
||||
@@ -145,6 +145,8 @@ interface I {
|
||||
fun iFun(): String = "I::iFun"
|
||||
}
|
||||
|
||||
fun I.iFunExt() = iFun()
|
||||
|
||||
private interface PI {
|
||||
fun piFun(): Any
|
||||
fun iFun(): String = "PI::iFun"
|
||||
@@ -261,4 +263,6 @@ class Bridge : BridgeBase() {
|
||||
override fun foo2() = throw MyException()
|
||||
override fun foo3() = throw MyException()
|
||||
override fun foo4() = throw MyException()
|
||||
}
|
||||
}
|
||||
|
||||
fun Any.same() = this
|
||||
|
||||
@@ -470,6 +470,26 @@ func testShared() throws {
|
||||
try assertNotFrozen(FinalClassExtOpen())
|
||||
}
|
||||
|
||||
class PureSwiftClass {
|
||||
}
|
||||
|
||||
struct PureSwiftStruct {
|
||||
var x: Int
|
||||
}
|
||||
class PureSwiftKotlinInterfaceImpl : I {
|
||||
func iFun() -> String {
|
||||
return "pure"
|
||||
}
|
||||
}
|
||||
|
||||
func testPureSwiftClasses() throws {
|
||||
let pureSwiftClass = PureSwiftClass()
|
||||
try assertTrue(ValuesKt.same(pureSwiftClass) as? AnyObject === pureSwiftClass)
|
||||
|
||||
try assertEquals(actual: 123, expected: (ValuesKt.same(PureSwiftStruct(x: 123)) as? PureSwiftStruct)?.x)
|
||||
try assertEquals(actual: "pure", expected: ValuesKt.iFunExt(PureSwiftKotlinInterfaceImpl()))
|
||||
}
|
||||
|
||||
// -------- Execution of the test --------
|
||||
|
||||
class ValuesTests : TestProvider {
|
||||
@@ -505,6 +525,7 @@ class ValuesTests : TestProvider {
|
||||
TestCase(name: "TestCompanionObj", method: withAutorelease(testCompanionObj)),
|
||||
TestCase(name: "TestInlineClasses", method: withAutorelease(testInlineClasses)),
|
||||
TestCase(name: "TestShared", method: withAutorelease(testShared)),
|
||||
TestCase(name: "TestPureSwiftClasses", method: withAutorelease(testPureSwiftClasses)),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +135,8 @@ static inline id AtomicSetAssociatedObject(ObjHeader* obj, id associatedObject)
|
||||
@interface KotlinBase : NSObject <ConvertibleToKotlin, NSCopying>
|
||||
@end;
|
||||
|
||||
static void initializeObjCExport();
|
||||
|
||||
@implementation KotlinBase {
|
||||
KRefSharedHolder refHolder;
|
||||
}
|
||||
@@ -144,6 +146,9 @@ static inline id AtomicSetAssociatedObject(ObjHeader* obj, id associatedObject)
|
||||
}
|
||||
|
||||
+(void)initialize {
|
||||
if (self == [KotlinBase class]) {
|
||||
initializeObjCExport();
|
||||
}
|
||||
initializeClass(self);
|
||||
}
|
||||
|
||||
@@ -376,16 +381,22 @@ static ALWAYS_INLINE OBJ_GETTER(convertUnmappedObjCObject, id obj) {
|
||||
static OBJ_GETTER(blockToKotlinImp, id self, SEL cmd);
|
||||
static OBJ_GETTER(boxedBooleanToKotlinImp, NSNumber* self, SEL cmd);
|
||||
|
||||
static OBJ_GETTER(SwiftObject_toKotlinImp, id self, SEL cmd);
|
||||
static void SwiftObject_releaseAsAssociatedObjectImp(id self, SEL cmd);
|
||||
|
||||
static void checkLoadedOnce();
|
||||
|
||||
static void initializeObjCExport() {
|
||||
checkLoadedOnce();
|
||||
|
||||
SEL toKotlinSelector = @selector(toKotlin:);
|
||||
Method toKotlinMethod = class_getClassMethod([NSObject class], toKotlinSelector);
|
||||
RuntimeAssert(toKotlinMethod != nullptr, "");
|
||||
const char* toKotlinTypeEncoding = method_getTypeEncoding(toKotlinMethod);
|
||||
|
||||
SEL releaseAsAssociatedObjectSelector = @selector(releaseAsAssociatedObject);
|
||||
Method releaseAsAssociatedObjectMethod = class_getClassMethod([NSObject class], releaseAsAssociatedObjectSelector);
|
||||
RuntimeAssert(releaseAsAssociatedObjectMethod != nullptr, "");
|
||||
const char* releaseAsAssociatedObjectTypeEncoding = method_getTypeEncoding(releaseAsAssociatedObjectMethod);
|
||||
|
||||
Class nsBlockClass = objc_getClass("NSBlock");
|
||||
RuntimeAssert(nsBlockClass != nullptr, "NSBlock class not found");
|
||||
|
||||
@@ -399,6 +410,20 @@ static void initializeObjCExport() {
|
||||
|
||||
added = class_addMethod(booleanClass, toKotlinSelector, (IMP)boxedBooleanToKotlinImp, toKotlinTypeEncoding);
|
||||
RuntimeAssert(added, "Unable to add 'toKotlin:' method to __NSCFBoolean class");
|
||||
|
||||
for (const char* swiftRootClassName : { "SwiftObject", "_TtCs12_SwiftObject" }) {
|
||||
Class swiftRootClass = objc_getClass(swiftRootClassName);
|
||||
if (swiftRootClass != nullptr) {
|
||||
added = class_addMethod(swiftRootClass, toKotlinSelector, (IMP)SwiftObject_toKotlinImp, toKotlinTypeEncoding);
|
||||
RuntimeAssert(added, "Unable to add 'toKotlin:' method to SwiftObject class");
|
||||
|
||||
added = class_addMethod(
|
||||
swiftRootClass, releaseAsAssociatedObjectSelector,
|
||||
(IMP)SwiftObject_releaseAsAssociatedObjectImp, releaseAsAssociatedObjectTypeEncoding
|
||||
);
|
||||
RuntimeAssert(added, "Unable to add 'releaseAsAssociatedObject' method to SwiftObject class");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@interface NSObject (NSObjectToKotlin) <ConvertibleToKotlin>
|
||||
@@ -416,11 +441,19 @@ static void initializeObjCExport() {
|
||||
+(void)load {
|
||||
static dispatch_once_t onceToken = 0;
|
||||
dispatch_once(&onceToken, ^{
|
||||
initializeObjCExport();
|
||||
checkLoadedOnce();
|
||||
});
|
||||
}
|
||||
@end;
|
||||
|
||||
static OBJ_GETTER(SwiftObject_toKotlinImp, id self, SEL cmd) {
|
||||
RETURN_RESULT_OF(convertUnmappedObjCObject, self);
|
||||
}
|
||||
|
||||
static void SwiftObject_releaseAsAssociatedObjectImp(id self, SEL cmd) {
|
||||
objc_release(self);
|
||||
}
|
||||
|
||||
@interface NSString (NSStringToKotlin) <ConvertibleToKotlin>
|
||||
@end;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user