Search code examples
swiftkotlininteropkotlin-multiplatformkotlin-native

Kotlin-Swift interop issue: ArrayList has wrong count value when passed as NSMutableArray from Swift Code for Release builds


Let's assume a KMP Project which is set to have a Sample iOS app in which a KMP module's output framework is added as a dependency.

I am having a function sampleFuncForStringArrayList(names: ArrayList<String>) in KMP module which prints count and iterates and print ArrayList items.

When I call this function from the iOS sample app, I am getting index out of bound exception because NSMutableArray count which is 2 in iOS app environment, has count as 24576 when received as ArrayList in KMP module.

This issue happens only with releaseFramework. debugFramework works fine.

//Swift
let namesStringList = NSMutableArray(array: ["Alice", "Bob"])
print("NSMutableArray COUNT : \(namesStringList.count)")
Main().sampleFuncForStringArrayList(names: namesStringList)


//Kotlin
public class Main {
    public fun sampleFuncForStringArrayList(names: ArrayList<String>){
        println("names.isNullOrEmpty() ${names.isNullOrEmpty()}")
        println("names.count ${names.count()}")
        names.forEach {
            println("Hello $it")
        }
    }
}

Expected Output

NSMutableArray COUNT : 2
names.isNullOrEmpty() false
names.count 2
Hello Alice
Hello Bob

Actual Output:

NSMutableArray COUNT : 2
names.isNullOrEmpty() false
names.count 24576
CRASH

- CRASH -

Sample Project ZIP: https://drive.google.com/file/d/1SgmW4hfeWaEeD3vcidnZ81Q9vMJsU9zJ/view?usp=sharing


Solution

  • I've tried with my KMM setup (using cocoapods) and even with a release build I got the right expected behaviour but I've used the right kotlin/swift interop mapping type MutableList

    fun sampleFuncForStringMutableList(names: MutableList<String>) {
        println("names.isNullOrEmpty() ${names.isNullOrEmpty()}")
        println("names.count ${names.count()}")
        names.forEach {
            println("Hello $it")
        }
    }
    

    With ArrayList I see an empty array and then a crash (different from debug build where I see your expected behaviour too).

    let namesStringList = NSMutableArray(array: ["Alice", "Bob"])
    print("NSMutableArray COUNT : \(namesStringList.count)")
    Main().sampleFuncForStringArrayList(names: namesStringList)
    Main().sampleFuncForStringMutableList(names: namesStringList)
    
    NSMutableArray COUNT : 2
    names.isNullOrEmpty() true
    names.count 0
    names.isNullOrEmpty() false
    names.count 2
    Hello Alice
    Hello Bob
    

    So I suggest you to use the right mapping type and not another one.