如何在Kotlin多平台移动的中使用Swift中的Flow的密封类数据?

sdnqo3pr  于 2022-10-31  发布在  Swift
关注(0)|答案(1)|浏览(262)

我无法访问Swift的Flow中观察到的密封类数据。

sealed class NetworkStatus<T> {

data class Loading<T>(var loading: Boolean) : NetworkStatus<T> ()

data class CustomSignal<T>(var signal: String) : NetworkStatus<T>()

data class CustomSignalDetailed<T>(var signal: ErrorCaseData) : NetworkStatus<T>()

data class Failure<T>(val e: Throwable) : NetworkStatus<T>()

data class Data<T> (val data: T ) : NetworkStatus<T>()

companion object {

    fun <T>loading(isLoading: Boolean): NetworkStatus<T> = Loading(isLoading)

    fun <T> customstatus(signal: String): NetworkStatus<T> = CustomSignal(signal)

    fun <T> customStatusDetailed(signals: ErrorCaseData): NetworkStatus<T> = CustomSignalDetailed(signals)

    fun <T> failure(e: Throwable): NetworkStatus<T> = Failure(e)

    fun <T> data(data: T): NetworkStatus<T> = Data<T>(data)
    }

}

https://gist.github.com/RageshAntony/a4fd357973485b5fb8aef0e189ee9e7e
在上面的要点....
在MainActivity.kt中,我在数据流中使用了密封类
现在我也需要Swift,但这很混乱
即使我用了一些东西作为CFlow Package ..仍然混乱
在Swift中,我无法获取仅作为nsarray的对象类型,并且NetworkStatus.data无法访问www.example.com
..我尝试了手动类型转换(在第8行,contentview.swift)
数据对象仍然没有任何类型...
请帮助我如何在Swift中实现与MainActivity.kt中相同的流程

9q78igpj

9q78igpj1#

从共享代码中声明的密封类开始:

sealed class KMMResult<out Value>

data class SuccessKMMResult<Value>(
    val value: Value
): KMMResult<Value>()

data class ErrorKMMResult<Value>(
    val throwable: Throwable
): KMMResult<Value>()

这个方法随机返回一个KMMResult,其中包含Success或Failure:

fun getRandomIntWrappedInResult(): KMMResult<Int> {
    val isSuccess = Random.nextBoolean()
    return if(isSuccess) {
      SuccessKMMResult(Random.nextInt(until = 10))
    } else {
        ErrorKMMResult(RuntimeException("There was an error, Int not generated"))
    }
}

您可以在Android上这样使用它:

val randomInt: KMMResult<Int> = getRandomIntWrappedInResult()
val randomIntText: String = when (randomInt) {
    is KMMResult.ErrorKMMResult -> {
        "Error: ${randomInt.throwable.message}"
    }
    is KMMResult.SuccessKMMResult -> {
        "Success: ${randomInt.value}"
    }
}

在iOS上是这样的:

let randomInt: KMMResult<KotlinInt> = RandomNumberGeneratorKt.getRandomIntWrappedInIntResult()
let randomIntText: String

switch randomInt {
case let error as KMMResultErrorKMMResult<KotlinInt>:
    randomIntText = "Error: \(error.throwable.message ?? error.throwable.description())"
case let success as KMMResultSuccessKMMResult<KotlinInt>:
    randomIntText = "Success: \(success.value)"
default:
    randomIntText = "This never happens"
}

这不是最好的解决方案,我建议您创建一个Swift枚举,如下所示:

enum SwiftResult<Value> {
  case error(String)
  case success(Value)
}

并使用以下公式将KMMResult转换为SwiftResult

func toSwiftResult<Value>(kmmResult: KMMResult<Value>) -> SwiftResult<Value> {
  if let successResult = kmmResult as? KMMResultSuccessKMMResult<Value> {
    return SwiftResult.success(successResult.value!)
  }
  if let errorResult = kmmResult as? KMMResultErrorKMMResult {
    return SwiftResult.error(errorResult.throwable.message ?? errorResult.throwable.description())
  }
  return SwiftResult.error("Unexpected error converting to SwiftResult")
}

不幸的是,您需要为每个密封类手动执行此操作,因此我建议您使用moko-kswift库,它可以为您完成此工作。
注意:避免使用List<Something>作为泛型类型,因为Something将被删除,当从Swift中看到该类型时,您将只看到NSArray。您可以使用两个类,一个用于单个项目,一个用于List,仍然是Something的泛型类型,或者您可以创建一个 Package 器数据类围绕您的列表,比如ListWrapper,这样该类型就不会被删除。因为原始的List<Something>将位于ListWrapper内,而ListWrapper将成为NetworkStatus的类型。
另一个附言:你的函数getAllCategories()在gist中返回了一个flow,所以它不应该是一个suspend函数。

相关问题