Skip to content

Instantly share code, notes, and snippets.

@AlexGladkov
Last active December 16, 2020 08:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlexGladkov/06d0d6f8280f97c7bf4b915fa946a9a1 to your computer and use it in GitHub Desktop.
Save AlexGladkov/06d0d6f8280f97c7bf4b915fa946a9a1 to your computer and use it in GitHub Desktop.
Coroutines + Rx (Multiplatform + iOS Native)
import LMCustomerSDK // Your Kotlin Multiplatform Library
import RxSwift
struct RxAsyncResult<ResultElement: AnyObject> {
#if targetEnvironment(simulator)
let async: AsyncResult<ResultElement>
#else
let async: AsyncResult
#endif
func asRxChain() -> Single<ResultElement> {
Single.create { (observer: @escaping (SingleEvent<ResultElement>) -> Void) in
let disposable = self.async.subscribe(
onSuccess: { (object: Any?) in
guard let object = object as? ResultElement else { return }
observer(.success(object))
},
onError: { throwable in
let customerSDKErrorWrapper = CustomerSDKErrorWrapper(throwable: throwable)
return observer(.error(customerSDKErrorWrapper))
}
)
return Disposables.create {
disposable.dispose()
}
}
}
}
// Error Wrapper
import LMCustomerSDK
struct CustomerSDKErrorWrapper: LocalizedError {
let throwable: KotlinThrowable
var errorDescription: String? {
throwable.message
}
}
// Use Case
RxAsyncResult<SomeSuspendFunctionReturnClassType>(async: someSuspendFunction()) // Here is your suspend function in MultiplatformModule
.asRxChain()
.observeOn(MainScheduler.instance)
.subscribe(onSuccess: { [weak self] response in
// Success flow
}, onError: { [weak self] error in
// Error flow
}).disposed(by: disposeBag)
// Multiplatform code
fun someSuspendFunction(request: SomeRequest): AsyncResult<SomeSuspendFunctionReturnClassType>
return AsyncResult.fromCoroutine {
someRepository.getSuspendFunction(request)
}
}
// AsyncResult Wrapper
class AsyncResult<Element>(
private val source: (Emitter<Element>) -> Unit
) {
fun subscribe(
onSuccess: (Element) -> Unit,
onError: (Throwable) -> Unit
): Disposable {
val emitter = Emitter(onSuccess, onError)
source.invoke(emitter)
return object : Disposable {
override fun dispose() {
emitter.disposable?.invoke()
}
}
}
interface Disposable {
fun dispose()
}
class Emitter<Element>(
val onSuccess: (Element) -> Unit,
val onError: (Throwable) -> Unit,
var disposable: (() -> Unit)? = null
)
companion object {
fun <Element> from(source: (Emitter<Element>) -> Unit): AsyncResult<Element> {
return AsyncResult(source)
}
}
}
// Extension
fun <Element> AsyncResult.Companion.fromCoroutine(
source: suspend () -> Element
): AsyncResult<Element> {
return from { emitter ->
val job = CoroutineScope(defaultDispatcher).launch {
try {
val result = source.invoke()
emitter.onSuccess(result)
} catch (error: Throwable) {
emitter.onError(error)
}
}
emitter.disposable = {
job.cancel()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment