Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 协同程序-避免使用挂起函数_Swift_Kotlin Coroutines_Coroutine_Kotlin Multiplatform_Kmm - Fatal编程技术网

Swift 协同程序-避免使用挂起函数

Swift 协同程序-避免使用挂起函数,swift,kotlin-coroutines,coroutine,kotlin-multiplatform,kmm,Swift,Kotlin Coroutines,Coroutine,Kotlin Multiplatform,Kmm,我不熟悉KMM和合作项目。是否有一种方法可以等待异步函数的响应,而无需使依赖函数也挂起 代码示例 // In HttpClient.kt in commonMain class MyHttpClient { val client = HttpClient() suspend fun get(url: String): String { client.get<String>(url) } } // In Another class in c

我不熟悉KMM和合作项目。是否有一种方法可以等待异步函数的响应,而无需使依赖函数也挂起

代码示例

// In HttpClient.kt in commonMain

class MyHttpClient {
    val client = HttpClient()

    suspend fun get(url: String): String {
        client.get<String>(url)
    }
}

// In Another class in commonMain
class Foo {
    private val httpClient = MyHttpClient()

    fun performAction() { <--- #1
        val data = httpClient.get("server url")
        // So stuff with that data after its retrieve from server.
    }
}

// In iOS swift code
struct Example: View {

    var body: some View {
        Button {
            foo.performAction() <--- #2
        } label: {
            Text("Click Me")
        }
    }

}

此外,我的单元测试失败,因为您无法使测试挂起函数,并且
运行阻塞
不在commonMain中。

您需要指定一个协同程序,在该程序上运行您的方法

class Foo {
    private val httpClient = MyHttpClient()
    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)

    fun performAction() {
        scope.launch {
            val data = httpClient.get("server url")
            // So stuff with that data after its retrieve from server.
        }
    }
}

您不需要添加完成回调。您只需从单击处理程序启动一个协同程序,如下所示:

    Button {
        viewScope.launch {
            foo.performAction()
            // add GUI code here that runs when action is done
        }
    } label: {
        Text("Click Me")
    }
如果您当前没有定义协同程序作用域,则应该这样添加它(大约):


Dispatchers.Main
使协同程序在GUI线程上运行。由于您使用的是suspendable IO(正如您的
suspend fun get(url:String):String所见证的那样),因此不需要使用任何其他线程。

这不是一个很好的示例,因为它破坏了结构化并发性——不仅在顶层,甚至在内部启动的协同程序中,它也不会成为外部线程的子线程。不要为每个协同程序创建临时作用域。@MarkoTopolnik谢谢你的评论,我更新了答案。我的评论主要是关于
MainScope()。不过,启动
。一个自包含的示例不一定显示将协同程序的生命周期链接到外部世界的正确方式,但它绝对可以避免破坏其自身的协同程序层次结构。@MarkoTopolnik我曾经与
MainScope
一起工作过,您能解释一下陷阱吗(可能给出一个链接),并演示如何切换到UI范围?如果取消外部协同程序,它将不会传播到内部协同程序,因为您没有提供继承的范围,而是创建了一个新的独立范围。UI不是作用域,而是调度器;这两个是正交关系。在OP的情况下,不需要切换,只需完全在GUI调度程序中运行即可。如果确实需要,可以从GUI调度程序开始,然后在阻塞操作周围使用
withContext(IO)
。但是,您应该主要避免像OP一样阻塞操作。
    Button {
        viewScope.launch {
            foo.performAction()
            // add GUI code here that runs when action is done
        }
    } label: {
        Text("Click Me")
    }
struct Example: View {
    private val viewScope = CoroutineScope(Dispatchers.Main)

    // adapt this to the actual way you get the "view closed" event
    fun onClose() { 
        viewScope.cancel()
    ​}

   ​...
}