#swift #kotlin #kotlin-coroutines #kotlin-multiplatform
#swift #котлин #kotlin-сопрограммы #kotlin-мультиплатформенный
Вопрос:
Я использую Kotlin-Native с поддержкой сопрограмм native-mt и библиотекой Ktor. У меня есть несколько приостановленных функций, которые принимают объект, построенный с использованием шаблона builder. Я понимаю, что мне нужно вызвать приостановленную функцию в потоке main / ui. Однако я не могу гарантировать, что объекты builder будут созданы в этом потоке. Насколько я понимаю, они должны быть заморожены перед отправкой в основной поток для вызова с приостановленной функцией. Это правильно?
Например, это приведет к сбою из-за того, что объект запроса не был заморожен:
func loadData() {
DispatchQueue.global(qos: .background).async {
let query = CustomerQuery().emails(value: ["customer@gmail.com"])
self.fetchCustomersAndDoSomething(query: query)
}
}
func fetchCustomersAndDoSomething(query: CustomerQuery) {
DispatchQueue.main.async {
self.mylibrary.getCustomers(query: query) { response, err in
// do something with response
}
}
}
Если это правда, правильно ли я понимаю, что мне нужно будет добавить метод к каждому такому объекту, чтобы «заморозить» его, поскольку функция freeze()
Kotlin from Freezing.kt
, похоже, недоступна из кода Swift, импортирующего мою библиотеку? Это еще более осложняется тем фактом, что замораживание относится только к коду iOS, так как код Android в этом не нуждается.
Есть ли более простой способ передать объекты Kotlin, созданные Swift, в приостановленную функцию, не требуя, чтобы эти объекты создавались в основном потоке?
Ответ №1:
В Kotlin / Native world всякий раз, когда вы делитесь объектами между потоками, вы должны убедиться, что они заморожены (неизменяемы), если вы не планируете их @ThreadLocal
создавать. Android является исключением, поскольку JVM не такая строгая, и позволяет вам делиться изменяемыми объектами между потоками.
У вас есть два варианта:
- Либо предоставьте
freeze()
функцию и используйте ее freeze()
каждый входящий объект в вашем общем коде
Кроме того, если вы не зависнете, вероятно, вы столкнетесь с IncorrectDereferenceException
, что означает, что вы пытаетесь поделиться изменяемым / незамороженным состоянием
Комментарии:
1. Означает ли это, что для варианта 2, практически говоря, я не могу вызывать приостановленные функции из Swift, если они принимают объекты, которые я не могу гарантировать, заморожены?
Ответ №2:
Вы не замораживаете быстрые занятия. Если CustomerQuery
это класс Kotlin, вам нужно будет заморозить его.
Однако вам нужно вызывать функции приостановки в основном потоке только в том случае, если вы полагаетесь на автоматически сгенерированный Objc-интерфейс компилятора Kotlin. Обычно мы рекомендуем не делать этого, потому что вы не можете контролировать жизненный цикл, но это уже совсем другой разговор.
Комментарии:
1. Да, я понимаю, что вы не стали бы замораживать быстрые занятия. Судя по тому факту, что приостановленная функция принимает объект, это должен быть класс Kotlin. Какова лучшая альтернатива использованию интерфейса objc при вызове приостановленных функций из Swift?
2. Ну, если
CustomerQuery
бы это соответствовало интерфейсу Kotlin, вы могли бы передать это. Однако, похожеCustomerQuery
, что это класс Kotlin, и в этом случае его нужно будет заморозить, а ответ от Nagy имеет больше вариантов. Альтернативой для приостановки является написание собственного интерфейса, который управляет областью действия для сопрограмм. Больше работы, но вы можете контролировать жизненный цикл: github.com/touchlab/KaMPKit/blob/master/shared/src/iosMain /…3. Хорошо, спасибо — это то, чего я боялся.