-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to create observables in iOS views? #664
Comments
The best way is to create subjects (e.g. One approach is to create an abstract view class in Kotlin which would hold subjects privately, and expose Another possible way is to create subject wrapper classes in Kotlin. They can be used in Swift, either directly or for interop with RxSwift. class PublishSubjectWrapper<T : Any> private constructor(
subject: PublishSubject<T>
) : ObservableWrapper<T>(subject), ObservableCallbacks<T> by subject {
constructor() : this(PublishSubject())
} Then your View interface would look something like: interface SampleView {
val reloadTrigger: ObservableWrapper<Unit>
val sortTrigger: ObservableWrapper<Boolean>
} Your Android code: class SampleFragment : Fragment, SampleView {
override val reloadTrigger: ObservableWrapper<Unit>
get() = binding.swipeRefreshLayout.refreshes().asReaktiveObservable().wrap()
override val sortTrigger: ObservableWrapper<Boolean>
get() = binding.sortingCheckbox.checkedChanges().asReaktiveObservable().wrap()
} And in Swift you can actually use |
We gave it a try, but our main problem that blocked us in the end is that we don't know how to "map" RxSwift observables to fields of type ObservableWrapper which are defined in SampleView interface: final class SampleViewController: SampleView {
var reloadTrigger: ObservableWrapper<KotlinUnit> {
refreshControl.rx.controlEvent(.valueChanged) // How to transform this to ObservableWrapper?
}
var sortTrigger: ObservableWrapper<Bool> {
sortingToggle.rx.isOn // How to transform this to ObservableWrapper?
}
} How to transform observables exposed by RxSwift to ObservableWrappers on the Swift side? Is it even possible? We couldn’t manage to do that because |
This could be done in multiple ways, assuming you are using RxSwift.
// This is code is approximate, I didn't have a chance to try it
extension RxSwift.Observable where Element : AnyObject {
func wrap(_ bag: DisposeBag) -> ObservableWrapper<Element> {
let subj = PublishSubjectWrapper<Element>()
self.subscribe(onNext: subj.onNext).addDisposableTo(bag)
return subj
}
}
// In Kotlin
class MyObservableWrapper<T: Any>(onSubscribe: (ObservableEmitterWrapper<T>) -> Unit) : ObservableWrapper<T>(
observable { emitter ->
onSubscribe(ObservableEmitterWrapper(emitter))
}
)
class ObservableEmitterWrapper<T>(emitter: ObservableEmitter<T>) : ObservableEmitter<T> by emitter // In Swift. This is code is approximate, I didn't have a chance to try it.
extension RxSwift.Observable where Element : AnyObject {
func wrap() -> ObservableWrapper<Element> {
return MyObservableWrapper { emitter in
let disposable = self.subscribe(onNext: emitter.onNext, onCompleted: emitter.onComplete)
emitter.setDisposable(...) // TODO: convert RxSwift Disposable to Reaktive Disposable
}
}
} If the second approach is more preferable, we could add the first (Kotlin) snippet to the library, so only the second (Swift) would be required on client side. |
There is also another way of creating Add the following Kotlin class: class CallbackObservable<out T : Any>(
onSubscribe: (
onNext: (T) -> Unit,
onComplete: () -> Unit,
onError: (Throwable) -> Unit,
setDisposable: (Disposable) -> Unit,
) -> Unit
) : ObservableWrapper<T>(
observable { emitter ->
onSubscribe(
emitter::onNext,
emitter::onComplete,
emitter::onError,
emitter::setDisposable,
)
}
) This class can be used in Swift to create For example: class SampleViewController : SampleView {
var reloadTrigger: ObservableWrapper<KotlinUnit> {
CallbackObservable { onNext, onComplete, onError, setDisposable in
// Susbcribe to a Swift stream here
}
}
} |
Hi @arkivanov thank you for your job in KMM. I try to convert RxSwift Observable in Reaktive ObservableWrapper with this method you suggested: extension RxSwift.Observable where Element : AnyObject {
func wrap() -> ObservableWrapper<Element> {
return MyObservableWrapper { emitter in
let disposable = self.subscribe(onNext: emitter.onNext, onCompleted: emitter.onComplete)
emitter.setDisposable(...) // TODO: convert RxSwift Disposable to Reaktive Disposable
}
}
} But I cannot understand how to convert RxSwift Disposable to Reaktive Disposable. I try with following code: let disposableScope = shared.DisposableScopeBuilderKt.disposableScope { _ in
disposable.dispose()
}
emitter.setDisposable(disposable: disposableScope) But as soon as I subscribe to ObservableWrapper, |
@flaviosuardi Actually there could be a better way, you can try using Emitter.setCancellable extension function, instead of This is an example from the top of my head: EmitterExtKt.setCancellable(emitter, disposable.dispose) |
I'm not sure how to create Observables, Singles etc. in iOS views.
Let's say this is in my shared module:
And this would be the android implementation:
But how to create fields like reloadTrigger or sortTrigger in an iOS view using Swift? Is it even possible, or does the communication between the iOS layer and shared layer need to be non-reaktive? If it's possible, is there any sample with this approach I could check out?
The text was updated successfully, but these errors were encountered: