https://kotlinlang.org logo
#multiplatform
Title
# multiplatform
m

Michael Pohl

11/09/2020, 3:26 PM
Hi everyone! Maybe someone can help me out with what are probably Multiplatform beginner questions... I just went through the Kotlin Multiplatform Hands-on: Networking and Data Storage tutorial. the Android build is running, but iOS crashes at startup. I've been double and triple checking everything but I cannot find anything I did wrong. Tbh, I also have trouble understanding what the stacktrace tells me (as in: Which of the mentioned classes in there is the origin of the problem):
Copy code
Function doesn't have or inherit @Throws annotation and thus exception isn't propagated from Kotlin to Objective-C/Swift as NSError.
It is considered unexpected and unhandled instead. Program will be terminated.
Uncaught Kotlin exception: kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen kotlinx.coroutines.ChildHandleNode@12e2608
    at 0   shared                              0x0000000104b05f7d kfun:kotlin.Throwable#<init>(kotlin.String?){} + 93 (/Users/teamcity/buildAgent/work/cae0e6559deed4c4/runtime/src/main/kotlin/kotlin/Throwable.kt:23:37)
    at 1   shared                              0x0000000104afeb2b kfun:kotlin.Exception#<init>(kotlin.String?){} + 91 (/Users/teamcity/buildAgent/work/cae0e6559deed4c4/runtime/src/main/kotlin/kotlin/Exceptions.kt:23:44)
    at 2   shared                              0x0000000104afed7b kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 91 (/Users/teamcity/buildAgent/work/cae0e6559deed4c4/runtime/src/main/kotlin/kotlin/Exceptions.kt:34:44)
    at 3   shared                              0x0000000104b3520b kfun:kotlin.native.concurrent.InvalidMutabilityException#<init>(kotlin.String){} + 91 (/Users/teamcity/buildAgent/work/cae0e6559deed4c4/runtime/src/main/kotlin/kotlin/native/concurrent/Freezing.kt:22:60)
    at 4   shared                              0x0000000104b356e2 ThrowInvalidMutabilityException + 690 (/Users/teamcity/buildAgent/work/cae0e6559deed4c4/runtime/src/main/kotlin/kotlin/native/concurrent/Internal.kt:92:11)
    at 5   shared                              0x0000000104c2958c MutationCheck + 108
    at 6   shared                              0x0000000104d167b6 kfun:kotlinx.coroutines.internal.LinkedListNode#<set-_next>(kotlinx.coroutines.internal.LinkedListNode){} + 102 (/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/native/src/internal/LinkedList.kt:19:28)
    at 7   shared                              0x0000000104d16b3b kfun:kotlinx.coroutines.internal.LinkedListNode#addLast(kotlinx.coroutines.internal.LinkedListNode){} + 283 (/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/native/src/internal/LinkedList.kt:31:9)
    at 8   shared                              0x0000000104d16e86 kfun:kotlinx.coroutines.internal.LinkedListNode#addOneIfEmpty(kotlinx.coroutines.internal.LinkedListNode){}kotlin.Boolean + 230 (/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/native/src/internal/LinkedList.kt:47:9)
    at 9   shared                              0x0000000104cc6ecf kfun:kotlinx.coroutines.JobSupport.promoteSingleToNodeList#internal + 463 (/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt:532:15)
    at 10  shared                              0x0000000104cc5b2d kfun:kotlinx.coroutines.JobSupport#invokeOnCompletion(kotlin.Boolean;kotlin.Boolean;kotlin.Function1<kotlin.Throwable?,kotlin.Unit>){}kotlinx.coroutines.DisposableHandle + 2061 (/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt:470:25)
    at 11  shared                              0x0000000104cc529f kfun:kotlinx.coroutines.JobSupport#invokeOnCompletion(kotlin.Function1<kotlin.Throwable?,kotlin.Unit>){}kotlinx.coroutines.DisposableHandle + 207 (/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt:449:9)
    at 12  shared                              0x0000000104e62d14 kfun:io.ktor.client#HttpClient(io.ktor.client.engine.HttpClientEngineFactory<0:0>;kotlin.Function1<io.ktor.client.HttpClientConfig<0:0>,kotlin.Unit>){0§<io.ktor.client.engine.HttpClientEngineConfig>}io.ktor.client.HttpClient + 1156 (/opt/buildAgent/work/a85294440dc5c6e/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClient.kt:45:36)
    at 13  shared                              0x0000000104ea5d0e kfun:io.ktor.client#HttpClient(kotlin.Function1<io.ktor.client.HttpClientConfig<*>,kotlin.Unit>){}io.ktor.client.HttpClient + 638 (/opt/buildAgent/work/a85294440dc5c6e/ktor-client/ktor-client-core/posix/src/io/ktor/client/HttpClient.kt:18:46)
    at 14  shared                              0x0000000104a7ad67 kfun:com.example.multiplatformtest.shared.network.SpaceXApi#<init>(){} + 199
    at 15  shared                              0x0000000104a6e6a7 kfun:com.example.multiplatformtest.shared.SpaceXSDK#<init>(com.example.multiplatformtest.shared.cache.DatabaseDriverFactory){} + 327
    at 16  shared                              0x0000000104a7f6a8 objc2kotlin.12 + 232
    at 17  iosApp                              0x000000010497e9f7 $sSo15SharedSpaceXSDKC21databaseDriverFactoryABSo0a8DatabaseeF0C_tcfC + 39
    at 18  iosApp                              0x000000010497f4cb $s6iosApp13SceneDelegateCACycfc + 219 (/Users/michaelpohl/Development/Misc/MultiplatformTest/iosApp/iosApp/SceneDelegate.swift:5:0)
    at 19  iosApp                              0x000000010497f573 $s6iosApp13SceneDelegateCACycfcTo + 19
    at 20  UIKitCore                           0x000000010ecde71d -[UIScene initWithSession:connectionOptions:] + 709
    at 21  UIKitCore                           0x000000010fb0976b -[UIWindowScene initWithSession:connectionOptions:] + 88
    at 22  UIKitCore                           0x000000010ece1f12 +[UIScene _sceneForFBSScene:create:withSession:connectionOptions:] + 627
    at 23  UIKitCore                           0x000000010f88142b -[UIApplication _connectUISceneFromFBSScene:transitionContext:] + 1114
    at 24  UIKitCore                           0x000000010f88175a -[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 289
    at 25  UIKitCore                           0x000000010f370c27 -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 358
    at 26  FrontBoardServices                  0x0000000115d3a146 -[FBSScene _callOutQueue_agent_didCreateWithTransitionContext:completion:] + 391
    at 27  FrontBoardServices                  0x0000000115d62c0d __94-[FBSWorkspaceScenesClient createWithSceneID:groupID:parameters:transitionContext:completion:]_block_invoke.176 + 102
    at 28  FrontBoardServices                  0x0000000115d47ba1 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 209
    at 29  FrontBoardServices                  0x0000000115d628db __94-[FBSWorkspaceScenesClient createWithSceneID:groupID:parameters:transitionContext:completion:]_block_invoke + 352
I understand that I need the @Throws annotation for iOS to understand Exceptions, but where am I missing any? If I got right what I've built going through the tutorial there is
SpaceXSDK
as the single point of entry to the shared module, which one function is correctly anntoated. I was unable to find a guide to debugging such problems properly, is there a good resource on this? Other things I noticed: The
DatabaseDriverFactory
in the iOS package shows
com.squareup.sqldelight.drivers
as an unresolved reference, but it looks like that's an IDE error? Same about the
AppDataBase.kt
generated by SqolDelight. It exists in the build folder, and since at least the Android side compiles just fine, I assume it works correctly. Just wondering if that can also be generated into the actual source, so that I don't have n IDE error...? any insights are much appreciated!
oh ,if anyone is interested, here's a link to my code (it's just what I built following the tutorial):
s

Samuel Michael

11/09/2020, 3:48 PM
@Throws(Exception::class) suspend fun getLaunches(forceReload: Boolean): List<RocketLaunch> { val cachedLaunches = database.getAllLaunches() return if (cachedLaunches.isNotEmpty() && !forceReload) { cachedLaunches } else { api.getAllLaunches().also { database.clearDatabase() database.createLaunches(it) } } }
Slide in BuildingSDK page of tutorial
Nevermind that sounds like more of a concurrency/thread issue, see you have the correct annotation I mentioned above
m

Michael Pohl

11/09/2020, 3:57 PM
yes I do. I am actually wondering if this might be caused by any of the libraries, given that this is all fast-moving and very alpha. But I haven't fully grasped Mutliplatform yet, so I'm a little lost atm.
s

Sam

11/09/2020, 5:19 PM
Are you using any threading or Grand Central Dispatch in your code? A Kotlin object must be frozen before passing it between threads.
m

Michael Pohl

11/09/2020, 9:51 PM
I don't think so. As stated above, I just followed this very basic tutorial provided by jetbrains, there is just a single api call and very basic ui.
Ok, I've figured it out myself now. Android Studio automatically added the import statements as I was typing, but didn't always pick the correct one. So I had to go through all the files and double-check the imports, since it all looked correct in the IDE.
4 Views