Native: get rid of __NSCFBoolean references in ObjCExport

ObjCExport accessed `__NSCFBoolean` using
`objc_getClass("__NSCFBoolean")`. This class is a private API.
Remove this private API usage by getting the same class from
`[[NSNumber numberWithBool:YES] class]` instead.

Also remove `__NSCFBoolean` from the related error messages.

`__NSCFBoolean` didn't cause Kotlin-compiled apps to be rejected by
Apple, but this commit reduces the risk that this might happen in the
future, and addresses related user concerns.

^KT-62091
This commit is contained in:
Svyatoslav Scherbina
2023-11-21 12:07:16 +01:00
committed by Space Team
parent 707a650de1
commit d15ee71b6c
@@ -329,12 +329,20 @@ static void Kotlin_ObjCExport_initializeImpl() {
BOOL added = class_addMethod(nsBlockClass, toKotlinSelector, (IMP)blockToKotlinImp, toKotlinTypeEncoding);
RuntimeAssert(added, "Unable to add 'toKotlin:' method to NSBlock class");
// Note: __NSCFBoolean is not visible to linker, so this case can't be handled with a category too.
Class booleanClass = objc_getClass("__NSCFBoolean");
RuntimeAssert(booleanClass != nullptr, "__NSCFBoolean class not found");
// Note: the boolean class is not visible to linker, so this case can't be handled with a category too.
// Referring it directly is also undesirable, because this is "private API" (see e.g. KT-62091).
// Get the class from an object instead:
Class booleanClass = [[NSNumber numberWithBool:YES] class];
RuntimeAssert(booleanClass != nullptr, "The NS boolean class not found");
added = class_addMethod(booleanClass, toKotlinSelector, (IMP)boxedBooleanToKotlinImp, toKotlinTypeEncoding);
RuntimeAssert(added, "Unable to add 'toKotlin:' method to __NSCFBoolean class");
if (booleanClass != [[NSNumber numberWithInt:1] class]) {
added = class_addMethod(booleanClass, toKotlinSelector, (IMP)boxedBooleanToKotlinImp, toKotlinTypeEncoding);
RuntimeAssert(added, "Unable to add 'toKotlin:' method to the NS boolean class");
} else {
// Shouldn't really happen unless something changed in the implementation.
// Play safe in that case, don't botch the numbers case.
RuntimeAssert(false, "NSNumber uses the same class for booleans and numbers: %s", class_getName(booleanClass));
}
for (const char* swiftRootClassName : { "SwiftObject", "_TtCs12_SwiftObject" }) {
Class swiftRootClass = objc_getClass(swiftRootClassName);