KMM向iOS抛出自定义Throwable:除返回对象外的更优方案?
解决KMM自定义Throwable在iOS端无法直接获取的问题
在KMM中抛出自定义Throwable时,iOS端的completionHandler只能接收到通用的NSError/Error对象,无法直接获取自定义异常的专属属性(比如示例里的code)。虽然可以通过让updateData()直接返回CustomError对象来实现需求,但以下几种方案更符合KMM跨平台设计的最佳实践:
方案1:用密封类封装结果(Result模式)
这是KMM跨平台处理成功/失败场景的标准方案,通过密封类统一封装操作结果,避免依赖异常抛出机制,同时让iOS端能直接获取自定义错误信息。
KMM代码实现
sealed class Result<out T> { data class Success<out T>(val data: T) : Result<T>() data class Failure(val error: CustomError) : Result<Nothing>() } class CustomError(val message: String, val code: Int) class Greetings { suspend fun updateData(): Result<Unit> { return Result.Failure(CustomError("This is the customised error msg", 123)) } }
iOS代码调用
Greetings().updateData { result in switch result { case .success: // 处理成功逻辑 print("Update succeeded") case .failure(let error): // 直接获取自定义错误的属性 print("Error message: \(error.message), code: \(error.code)") } }
方案2:扩展NSError注入自定义属性
如果仍想保留异常抛出的方式,可以通过Kotlin的expect/actual机制,把自定义异常的属性注入到iOS端NSError的userInfo字典中,让iOS端能从通用Error中提取自定义信息。
KMM代码实现
// commonMain expect class CustomError(message: String, code: Int) : Throwable // iosMain import platform.Foundation.NSError import platform.Foundation.NSLocalizedDescriptionKey actual class CustomError actual constructor(message: String, val code: Int) : Throwable(message) { override fun fillInStackTrace(): Throwable { // 将自定义code注入到NSError的userInfo中 val userInfo = mapOf( "customErrorCode" to code, NSLocalizedDescriptionKey to message ) return NSError(domain = "com.yourdomain.customerrors", code = code, userInfo = userInfo) as Throwable } } class Greetings { @Throws(Throwable::class) suspend fun updateData() { throw CustomError("This is the customised error msg", 123) } }
iOS代码调用
Greetings().updateData { error in if let nsError = error as NSError? { let customCode = nsError.userInfo["customErrorCode"] as? Int ?? -1 let errorMessage = nsError.localizedDescription print("Error message: \(errorMessage), custom code: \(customCode)") } }
方案3:序列化自定义异常
通过Kotlinx Serialization将自定义异常序列化,抛出时传递序列化后的内容,iOS端反序列化获取完整信息。这种方案适合需要传递复杂错误结构的场景,但需要额外配置序列化插件。
KMM代码实现
首先在build.gradle.kts中添加序列化依赖:
plugins { kotlin("multiplatform") kotlin("plugin.serialization") version "1.9.20" } // 在commonMain依赖中添加 implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.0")
然后定义可序列化的自定义异常:
import kotlinx.serialization.Serializable @Serializable class CustomError(val message: String, val code: Int) : Throwable(message) class Greetings { @Throws(Throwable::class) suspend fun updateData() { throw CustomError("This is the customised error msg", 123) } }
iOS代码调用
借助Kotlinx Serialization的iOS端支持,将接收到的NSError中的异常信息反序列化:
import KotlinxSerialization Greetings().updateData { error in if let nsError = error as NSError?, let errorData = nsError.userInfo["KotlinException"] as? Data, let customError = try? JSONDecoder().decode(CustomError.self, from: errorData) { print("Error message: \(customError.message), code: \(customError.code)") } }
内容的提问来源于stack exchange,提问作者Ashwani Kumar
相关产品推荐
相关产品推荐

