Hi all, this code works `actual typealias Platform...
# multiplatform
d
Hi all, this code works
actual typealias PlatformDateTime = NSDate
, but I cannot do
actual typealias PlatformUByte = UInt8
, why? I want to avoid the Swift side needing to use KotlinUByteArray. I already achieved similar thing in the past with NSDate and NSData, but not seeing the way with UByte
m
You're encountering this issue because
NSDate
(and
NSData
) are Objective-C types, and Kotlin Multiplatform has special handling for bridging between Kotlin types and Objective-C types.
UInt8
(and other Swift/Objective-C numeric types) are bridged more directly, and the bridging for unsigned types is more complex. You can't directly
typealias
a Kotlin
UByte
to a Swift/Objective-C
UInt8
in the same way. Why it doesn't work: • Objective-C Bridging: Kotlin Multiplatform's interop with Objective-C is highly optimized. It recognizes
NSDate
and
NSData
as special cases and handles their conversion smoothly. This is because they are fundamental Foundation types. • Direct Type Mapping: For other types, especially numeric types, the mapping is often more direct.
UByte
in Kotlin is an unsigned 8-bit integer, but the way it's represented at the binary level and how Swift/Objective-C handles
UInt8
is not a perfect match for a direct
typealias
. The compiler and runtime need to perform conversions. • Unsigned Type Complexity: Unsigned types are handled slightly differently in Swift/Objective-C and Kotlin. The bridging mechanism has to account for these differences, which makes a simple
typealias
impossible. How to navigate this: • Using
expect/actual
Functions:
This is the cleanest and most idiomatic Kotlin Multiplatform approach. Define an
expect
function in your common code and provide
actual
implementations for each platform.
Copy code
// in commonMain
expect fun convertToPlatformUByteArray(byteArray: UByteArray): Any // Expect an Any type

// iosMain
actual fun convertToPlatformUByteArray(byteArray: UByteArray): NSData {
    val data = NSMutableData()
    for (byte in byteArray) {
        data.append([byte], 1) // Append each byte
    }
    return data
}

// Other platforms (if needed)
actual fun convertToPlatformUByteArray(byteArray: UByteArray): ByteArray { // Or a different type
    return byteArray.toByteArray() // Example for JVM
}

// Usage (common code)
val uByteArray = ubyteArrayOf(1u, 2u, 3u)
val platformByteArray = convertToPlatformUByteArray(uByteArray)
You can also check
Kotlin
source code of how they implemented the above on https://github.com/JetBrains/kotlin/blob/48fa3bda57e610d7376a1cba649c7da6387554f9/libraries/stdlib/src/kotlin/io/encoding/Base64.kt#L821C28-L821C53Using Intermediate Type: You could create an intermediate type that is common across platforms and then convert to/from it. This is more complex but might be useful in certain scenarios.
Copy code
// commonMain
data class ByteArrayWrapper(val bytes: ByteArray)

expect fun wrapUByteArray(byteArray: UByteArray): ByteArrayWrapper

// iosMain
actual fun wrapUByteArray(byteArray: UByteArray): ByteArrayWrapper {
    return ByteArrayWrapper(byteArray.toByteArray()) // Convert to regular ByteArray
}

// Usage
val uByteArray = ubyteArrayOf(1u, 2u, 3u)
val wrapper = wrapUByteArray(uByteArray)
val swiftData = wrapper.bytes.toNSData() // Swift extension to convert ByteArray to NSData
Hope this helps