swiftkotlincocoapods

Why The singleton in KMP is two different instances in iOS and Kotlin Mutliple Platform


I got an object(singleton) in kotlin Multiple platform(KMP)

Like:

object SqIOSApiRegister {

    private var initialized = false

    val lock = NSLock()
    init {
        if (initialized) {
            println("wwq ⚠️ ALREADY INITIALIZED!")
        } else {
            initialized = true
            println("wwq ✅ FIRST INIT")
        }
        println("wwqINIT")
    }

    private val serveMap = mutableMapOf<String, Any?>()

    private val singleMap: SqSmartWeakMap<String, IRegisterInfo> = SqSmartWeakMap()

    fun <T> registerSharedApi(clazz: String, objectValue: T) = lock.withLock {
        println("REGISTRATION - Thread: ${SqIOSApiRegister.hashCode()} - Object identity hash: ${SqIOSApiRegister.identityHashCode()} \n")
        println("wwqS11+${clazz}   \n")
        println("wwqS2+${SqIOSApiRegister.serveMap}  \n")
        println("wwqS3+${SqIOSApiRegister.serveMap.identityHashCode()}  \n")
        println("wwqS4+${SqIOSApiRegister.serveMap[clazz]}  \n")
        serveMap[clazz] = objectValue
    }

    fun getSharedApiSafely(clazz: String): Any? = lock.withLock {
        println("RETRIEVAL - Thread: ${SqIOSApiRegister.hashCode()} - Object identity hash: ${SqIOSApiRegister.identityHashCode()}\n")
        println("wwqS5+${clazz}   \n")
        println("wwqS6+${SqIOSApiRegister.serveMap}  \n")
        println("wwqS7+${SqIOSApiRegister.serveMap.identityHashCode()}  \n")
        println("wwqS8+${SqIOSApiRegister.serveMap[clazz]?.toString() ?: "null"}   \n")
        serveMap[clazz]
    }


    fun registerSingleApi(objectValue: IRegisterInfo) = lock.withLock {
        singleMap.put(objectValue.traceId, objectValue)
    }

    fun getSingleRegister(key: String): IRegisterInfo? = lock.withLock {
        singleMap.get(key)
    }
}

And I use it in my iOS code like this

SqIOSApiRegister.shared.registerSharedApi(clazz:KmpApiName.shared.accountName, objectValue: SQRKMPUserServiceManager.shareInstance)

but when I try to access it in KMP, it returns null

val net = SqIOSApiRegister.getSharedApiSafely(KmpApiName.netRequestName) as? INet

It seems like SqIOSApiRegister.shared is a different instance with KMP SqIOSApiRegister cause their identityHashCode() is different and SqIOSApiRegister.init method was called twice

This is my gradle:

    if (System.getProperty("os.name").lowercase().contains("mac")) {
        // Check if we're trying to build iOS targets
        val skipIos = project.hasProperty("skipIos") && project.property("skipIos") == "true"
        if (!skipIos) {
            try {
                listOf(
                    iosArm64(),
                ).forEach { iosTarget ->
                    iosTarget.binaries.framework {
                        baseName = "kmpBase"
                        isStatic = false
                        // 根据xcode环境属性决定输出路径
                        outputDirectory = layout.buildDirectory.get().asFile.resolve("myFrameworks")
                    }
                }
            } catch (e: Exception) {
                logger.warn("iOS targets disabled due to configuration issues: ${e.message}")
            }
        } else {
            logger.warn("iOS targets skipped by property")
        }
    } else {
        logger.warn("Not on macOS, skipping iOS targets")
    }

this is my podfile

pod 'kmpBase', :path =\> './SQRKMP'

Solution

  • Already Fix
    I wrapper two framework generated by KMP, you can only generate ONE