我尝试使用 Kotlin MPP(Multiplatform) 开发 Android 和 iOS 之间的共享库。但我面临着 iOS 中线程的问题。对于我在 iOS 中的应用程序,我在主线程中建立了对象,但它可能调用其他线程中的函数并抛出此异常,如下所示:
Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: illegal attempt to access non-shared example.api.DrivingBehaviorDetector@397cba8 from other thread
at 0 DrivingBehaviorDetector 0x00000001037619d7 kfun:kotlin.Throwable.<init>(kotlin.String?)kotlin.Throwable + 87
at 1 DrivingBehaviorDetector 0x000000010375bca5 kfun:kotlin.Exception.<init>(kotlin.String?)kotlin.Exception + 85
at 2 DrivingBehaviorDetector 0x000000010375b9a5 kfun:kotlin.RuntimeException.<init>(kotlin.String?)kotlin.RuntimeException + 85
at 3 DrivingBehaviorDetector 0x0000000103781395 kfun:kotlin.native.IncorrectDereferenceException.<init>(kotlin.String)kotlin.native.IncorrectDereferenceException + 85
at 4 DrivingBehaviorDetector 0x0000000103782568 ThrowIllegalObjectSharingException + 744
at 5 DrivingBehaviorDetector 0x00000001037d72bc _ZNK27BackRefFromAssociatedObject19ensureRefAccessibleEv + 76
at 6 DrivingBehaviorDetector 0x00000001037c97c3 -[KotlinBase toKotlin:] + 35
at 7 DrivingBehaviorDetector 0x00000001037e3ef1 Kotlin_ObjCExport_refFromObjC + 65
at 8 DrivingBehaviorDetector 0x00000001037c4e37 objc2kotlin.125 + 167
at 9 Test 0x000000010340224d $sIeg_IeyB_TR + 45 (/Users/james/Documents/Projects/go/TestMPPforiOS/<compiler-generated>:<unknown>)
at 10 libdispatch.dylib 0x0000000103959dd4 _dispatch_call_block_and_release + 12
at 11 libdispatch.dylib 0x000000010395ad48 _dispatch_client_callout + 8
at 12 libdispatch.dylib 0x000000010396c460 _dispatch_root_queue_drain + 819
at 13 libdispatch.dylib 0x000000010396cb96 _dispatch_worker_thread2 + 132
at 14 libsystem_pthread.dylib 0x00007fff5245f6b3 _pthread_wqthread + 583
at 15 libsystem_pthread.dylib 0x00007fff5245f3fd start_wqthread + 13
(lldb)
我在这些文章中调查了解决方案:
Kotlin/Native 中的不变性:Kotlin/Native 中的不变性 https://kotlinlang.org/docs/reference/native/immutability.html
协程和 K/N 的不变性:K/N 的协程和不变性 https://medium.com/quick-code/kotlin-native-ios-a1a73d7390fe.
我的API(共享库)的入口如下:
class DrivingBehaviorDetector (
private var gravity:Vector?,
private var front:Vector?,
onGravityOrFrontChanged: ((newGravity: Vector?, newFront: Vector?, timestamp: Long) -> Unit)?,
onDrivingEventDetected: ((event: DrivingEvent) -> Unit)?
) {
private val lowPassFilter = LowPassFilter()
private val accProcessor = AccProcessor(gravity, front, onGravityOrFrontChanged, onDrivingEventDetected)
init {
gravity = gravity?.toCoreUnit()
front = front?.toCoreUnit()
}
fun addData(data:Acceleration) {
val rawAcc = data.toCoreUnit()
val filterAcc = lowPassFilter.lowPass(rawAcc)
accProcessor.addData(filterAcc)
}
fun addData(data:List<Acceleration>) {
for(acc in data) {
addData(acc)
}
}
}
我们可以注意到 API 非常简单,只需输入大量数据并回调一些计算的结果即可。但在iOS中抛出异常,代码如下:
let drivingBehaviorDetector = DrivingBehaviorDetector(gravity: nil, front: nil, onGravityOrFrontChanged: { (newGravity, newFront, timestamp) in
print("newGravity = \(newGravity)")
print("newFront = \(newFront)")
}) { (event) in
print("event = \(event.description())")
}
let acc1 = Acceleration(vector: Vector(x: 0, y: 0, z: 0))
let acc2 = Acceleration(vector: Vector(x: 0, y: 100, z: 0))
drivingBehaviorDetector.addData(data: acc1)
DispatchQueue.global(qos: .background).async {
drivingBehaviorDetector.addData(data: acc2)
}
我能想到的唯一一个解决方案是强制在同一线程中使用 API,但这似乎有点奇怪。是否可以通过修改共享库来解决这个问题。因为 mu 的使用很简单,只有一个“DrivingBehaviorDetector”,但它可以在不同的线程中调用“addData”函数。谢谢回答。