【问题标题】:KMM IncorrectDereferenceException in Thread线程中的 KMM IncorrectDereferenceException
【发布时间】:2021-10-08 01:14:01
【问题描述】:

我一直在尝试使用共享模块 KMM 将图像上传到 aws s3 服务器。它在 Android 中运行良好,但在 iOS 中我遇到了这个问题:- Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: illegal attempt to access non-shared

现在,尽管我对此进行了多次搜索,但我知道它与 frozen() 的某些东西有关,但我不确定它是什么以及如何解决这个问题。

代码:-

actual class ClassName {

    init {
        ensureNeverFrozen()
    }

    actual fun imageUpload() {

        var credentialsProvider = AWSCognitoCredentialsProvider(regionType = // Region here, identityPoolId = //identityPoolId here)

        var configuration = AWSServiceConfiguration(region =  // Region here, credentialsProvider = //credentialsProvider here)

        AWSServiceManager.defaultServiceManager()?.defaultServiceConfiguration = configuration

        val expression = AWSS3TransferUtilityUploadExpression()

        // Start uploading using AWSS3TransferUtility
        val awsTransferUtility = AWSS3TransferUtility.defaultS3TransferUtility()
            val completionHandler: AWSS3TransferUtilityUploadCompletionHandlerBlock
            completionHandler = { _: AWSS3TransferUtilityUploadTask?, error: NSError? ->
                if (error == nil) {
                    val url = AWSS3.defaultS3().configuration.endpoint()?.URL()
                    val publicURL = url?.URLByAppendingPathComponent("bucketName")?.URLByAppendingPathComponent("fileName")
                    // Image Upload Complete
                } else {
                    // Image Upload failure
                }
            }
            awsTransferUtility.uploadFile(
                fileUrl!!,
                bucket = "bucketName",
                key = "fileName",
                contentType = ".image",
                expression = expression,
                completionHandler = completionHandler. // Error pointed on this line
            )
    }
}

现在,只要我调用该函数,我的应用就会崩溃,指向 completionHandler 的错误。

错误日志:-

Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: illegal attempt to access non-shared ClassName.$imageUpload$lambda-1$lambda-0$FUNCTION_REFERENCE$1@2803dc8 from other thread
    at 0   iosApp                              0x000000010cc1984f kfun:kotlin.Throwable#<init>(kotlin.String?){} + 95
    at 1   iosApp                              0x000000010cc138cd kfun:kotlin.Exception#<init>(kotlin.String?){} + 93
    at 2   iosApp                              0x000000010cc139fd kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 93
    at 3   iosApp                              0x000000010cc327fd kfun:kotlin.native.IncorrectDereferenceException#<init>(kotlin.String){} + 93
    at 4   iosApp                              0x000000010cc3461f ThrowIllegalObjectSharingException + 623
    at 5   iosApp                              0x000000010cd16fc2 _ZN12_GLOBAL__N_128throwIllegalSharingExceptionEP9ObjHeader + 34
    at 6   iosApp                              0x000000010cd170fd _ZN12_GLOBAL__N_136terminateWithIllegalSharingExceptionEP9ObjHeader + 13
    at 7   iosApp                              0x000000010cd1af0a _ZNK16KRefSharedHolder3refIL11ErrorPolicy3EEEP9ObjHeaderv + 58
    at 8   iosApp                              0x000000010cbf53ca _ZL39Kotlin_Interop_unwrapKotlinObjectHolderP11objc_object + 42
    at 9   iosApp                              0x000000010cbee050 _4b4d4d4c69623a736861726564_knbridge15 + 224
    at 10  AWSS3                               0x000000010d84509e -[AWSS3TransferUtility URLSession:task:didCompleteWithError:] + 4814

【问题讨论】:

  • 一种选择是在共享代码中编写接口,并在 swift 中实现生成的协议。这样你就可以绕过时髦的 kotlin 原生并发。通常 interface/impls 是一种更简洁的应用程序代码方法,而不是期望/实际。

标签: android ios swift kotlin-multiplatform awss3transferutility


【解决方案1】:

本机并发模型available 用于预览。查看New memory model migration guide。发布后您应该不会遇到任何此类问题,但在此之前,上述答案是有效的。


尝试拨打completionHandler.freeze()

或者,将处理程序移动到函数调用(不将其存储在变量中)。

如果您在处理程序中使用外部范围的一些变量,它们也可能需要被冻结。如果前两种方法都不起作用,请尝试仅用 print() 替换完成的内容,看看是否有帮助,如果有帮助 - 通过逐个取消注释部分代码来本地化有问题的行。

KMM 并发模型禁止从不同线程访问可变对象,freeze 使对象不可变,因此可以在不同线程中使用。

使用协程对象会在需要时自动冻结,但是当您在没有协程的情况下切换线程时,您必须自己动手。

这正是这里发生的事情:AWS 从另一个线程调用 completionHandler(这对于具有完成的方法很常见)

在此处查看有关并发模型的更多信息:https://kotlinlang.org/docs/mobile/concurrency-overview.html

这种行为是我们目前必须使用 KMM 管理的,但很快就会改变,这是 KMM 从 alpha 版到发布版的主要障碍,JetBrains 团队专注于解决这个特殊问题,所以我们不'不必再使用freeze()了。

【讨论】:

  • 嘿,感谢completionHandler.freeze() 的工作。但我不明白这里发生了什么。这是否意味着 KMM 为上传任务创建了一个单独的线程,而我的 iOS 代码位于单独的线程中,因此我无法使用我的 lambda 函数变量?还是别的什么?
  • @MohammedHanif。我已将解释添加到我的答案中,请查看
  • 非常感谢@Philip 的精彩解释
猜你喜欢
  • 2022-08-04
  • 2021-09-09
  • 2022-08-04
  • 1970-01-01
  • 1970-01-01
  • 2021-09-18
  • 2022-11-02
  • 1970-01-01
  • 2021-09-19
相关资源
最近更新 更多