From b12b6e1d60009fcc9634ff01937419dc5504cdaa Mon Sep 17 00:00:00 2001 From: Vasyl Pidlisniak Date: Tue, 1 Feb 2022 09:47:10 +0100 Subject: [PATCH 1/4] force main thread for Observable, Subject and LivecycleViewModel --- stencils/LifecycleViewModel.stencil | 9 ++++++++- stencils/Observable.stencil | 9 ++++++++- stencils/Subject.stencil | 9 ++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/stencils/LifecycleViewModel.stencil b/stencils/LifecycleViewModel.stencil index 4b2b4ad..291bca5 100644 --- a/stencils/LifecycleViewModel.stencil +++ b/stencils/LifecycleViewModel.stencil @@ -7,12 +7,19 @@ class LifecycleViewModel { let containerView: ContainerView? init(_ viewModel: VM, containerView: ContainerView? = nil) { + assert(Thread.isMainThread, "Constructor must be called on the main thread, but called on \(Thread.current)") self.viewModel = viewModel self.containerView = containerView } deinit { - viewModel.clear() + if Thread.current.isMainThread { + viewModel.clear() + } else { + DispatchQueue.main.sync { + viewModel.clear() + } + } } func lifecycleView(view: (VM) -> V) -> some View { diff --git a/stencils/Observable.stencil b/stencils/Observable.stencil index 39c91a4..0fe739a 100644 --- a/stencils/Observable.stencil +++ b/stencils/Observable.stencil @@ -29,6 +29,7 @@ class Observable: ObservableObject { animated: Bool = false, mapper: @escaping (Input) -> Output ) { + assert(Thread.isMainThread, "Constructor must be called on the main thread, but called on \(Thread.current)") input = observable.currentOrNull if input != nil { value = mapper(input!) @@ -59,7 +60,13 @@ class Observable: ObservableObject { } deinit { - disposeBag.dispose() + if (Thread.current.isMainThread) { + disposeBag.dispose() + } else { + DispatchQueue.main.sync { + disposeBag.dispose() + } + } } } diff --git a/stencils/Subject.stencil b/stencils/Subject.stencil index b089f94..5fb2652 100644 --- a/stencils/Subject.stencil +++ b/stencils/Subject.stencil @@ -25,6 +25,7 @@ class Subject: ObservableObject { toMapper: @escaping (Input) -> Output, fromMapper: @escaping (Output) -> Input ) { + assert(Thread.isMainThread, "Constructor must be called on the main thread, but called on \(Thread.current)") input = subject.currentOrNull if input != nil { value = toMapper(input!) @@ -61,7 +62,13 @@ class Subject: ObservableObject { } deinit { - disposeBag.dispose() + if (Thread.current.isMainThread) { + disposeBag.dispose() + } else { + DispatchQueue.main.sync { + disposeBag.dispose() + } + } } } From da113eab064c30c7dcc8d468ceb908c05f891103 Mon Sep 17 00:00:00 2001 From: Vasyl Pidlisniak Date: Tue, 1 Feb 2022 14:51:30 +0100 Subject: [PATCH 2/4] make calls async --- stencils/LifecycleViewModel.stencil | 5 +++-- stencils/Observable.stencil | 5 +++-- stencils/Subject.stencil | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/stencils/LifecycleViewModel.stencil b/stencils/LifecycleViewModel.stencil index 291bca5..a0ea16f 100644 --- a/stencils/LifecycleViewModel.stencil +++ b/stencils/LifecycleViewModel.stencil @@ -16,8 +16,9 @@ class LifecycleViewModel { if Thread.current.isMainThread { viewModel.clear() } else { - DispatchQueue.main.sync { - viewModel.clear() + let vm = viewModel + DispatchQueue.main.async { + vm.clear() } } } diff --git a/stencils/Observable.stencil b/stencils/Observable.stencil index 0fe739a..21457bc 100644 --- a/stencils/Observable.stencil +++ b/stencils/Observable.stencil @@ -63,8 +63,9 @@ class Observable: ObservableObject { if (Thread.current.isMainThread) { disposeBag.dispose() } else { - DispatchQueue.main.sync { - disposeBag.dispose() + let bag = disposeBag + DispatchQueue.main.async { + bag.dispose() } } } diff --git a/stencils/Subject.stencil b/stencils/Subject.stencil index 5fb2652..88b8190 100644 --- a/stencils/Subject.stencil +++ b/stencils/Subject.stencil @@ -65,8 +65,9 @@ class Subject: ObservableObject { if (Thread.current.isMainThread) { disposeBag.dispose() } else { - DispatchQueue.main.sync { - disposeBag.dispose() + let bag = disposeBag + DispatchQueue.main.async { + bag.dispose() } } } From 090ea171188cf0488fe92e7f49e4f63318129ba5 Mon Sep 17 00:00:00 2001 From: Vasyl Pidlisniak Date: Tue, 1 Feb 2022 15:23:38 +0100 Subject: [PATCH 3/4] always use async main thread for deinit --- stencils/LifecycleViewModel.stencil | 10 +++------- stencils/Observable.stencil | 10 +++------- stencils/Subject.stencil | 10 +++------- 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/stencils/LifecycleViewModel.stencil b/stencils/LifecycleViewModel.stencil index a0ea16f..07bdac6 100644 --- a/stencils/LifecycleViewModel.stencil +++ b/stencils/LifecycleViewModel.stencil @@ -13,13 +13,9 @@ class LifecycleViewModel { } deinit { - if Thread.current.isMainThread { - viewModel.clear() - } else { - let vm = viewModel - DispatchQueue.main.async { - vm.clear() - } + let vm = viewModel + DispatchQueue.main.async { + vm.clear() } } diff --git a/stencils/Observable.stencil b/stencils/Observable.stencil index 21457bc..29f1200 100644 --- a/stencils/Observable.stencil +++ b/stencils/Observable.stencil @@ -60,13 +60,9 @@ class Observable: ObservableObject { } deinit { - if (Thread.current.isMainThread) { - disposeBag.dispose() - } else { - let bag = disposeBag - DispatchQueue.main.async { - bag.dispose() - } + let bag = disposeBag + DispatchQueue.main.async { + bag.dispose() } } } diff --git a/stencils/Subject.stencil b/stencils/Subject.stencil index 88b8190..609cabd 100644 --- a/stencils/Subject.stencil +++ b/stencils/Subject.stencil @@ -62,13 +62,9 @@ class Subject: ObservableObject { } deinit { - if (Thread.current.isMainThread) { - disposeBag.dispose() - } else { - let bag = disposeBag - DispatchQueue.main.async { - bag.dispose() - } + let bag = disposeBag + DispatchQueue.main.async { + bag.dispose() } } } From 051d83ab3c9502b9e5b72e927bad785728573edc Mon Sep 17 00:00:00 2001 From: Vasyl Pidlisniak Date: Wed, 2 Feb 2022 10:50:56 +0100 Subject: [PATCH 4/4] added missing fixes for the rest of observables / subjects --- stencils/ListObservable.stencil | 6 +++++- stencils/ListSubject.stencil | 6 +++++- stencils/UninitializedObservable.stencil | 6 +++++- stencils/UninitializedSubject.stencil | 6 +++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/stencils/ListObservable.stencil b/stencils/ListObservable.stencil index 79636dc..137bd8c 100644 --- a/stencils/ListObservable.stencil +++ b/stencils/ListObservable.stencil @@ -17,6 +17,7 @@ class ListObservable: ObservableObject { animated: Bool = false, mapper: @escaping (NSArray) -> [Output] = ListMapper.to ) { + assert(Thread.isMainThread, "Constructor must be called on the main thread, but called on \(Thread.current)") input = observable.currentOrNull if input != nil { value = mapper(input!) @@ -48,7 +49,10 @@ class ListObservable: ObservableObject { } deinit { - disposeBag.dispose() + let bag = disposeBag + DispatchQueue.main.async { + bag.dispose() + } } } diff --git a/stencils/ListSubject.stencil b/stencils/ListSubject.stencil index 0f8cc89..8de4b74 100644 --- a/stencils/ListSubject.stencil +++ b/stencils/ListSubject.stencil @@ -18,6 +18,7 @@ class ListSubject: ObservableObject { animated: Bool = false, mapper: @escaping (NSArray) -> [Output] = ListMapper.to ) { + assert(Thread.isMainThread, "Constructor must be called on the main thread, but called on \(Thread.current)") input = subject.currentOrNull if input != nil { value = mapper(input!) @@ -54,7 +55,10 @@ class ListSubject: ObservableObject { } deinit { - disposeBag.dispose() + let bag = disposeBag + DispatchQueue.main.async { + bag.dispose() + } } } diff --git a/stencils/UninitializedObservable.stencil b/stencils/UninitializedObservable.stencil index b7a087b..9c16852 100644 --- a/stencils/UninitializedObservable.stencil +++ b/stencils/UninitializedObservable.stencil @@ -25,6 +25,7 @@ class UninitializedObservable: Observabl animated: Bool = false, mapper: @escaping (Input?) -> Output? ) { + assert(Thread.isMainThread, "Constructor must be called on the main thread, but called on \(Thread.current)") input = observable.currentOrNull if input != nil { value = mapper(input!) @@ -53,7 +54,10 @@ class UninitializedObservable: Observabl } deinit { - disposeBag.dispose() + let bag = disposeBag + DispatchQueue.main.async { + bag.dispose() + } } } diff --git a/stencils/UninitializedSubject.stencil b/stencils/UninitializedSubject.stencil index d420558..82613d0 100644 --- a/stencils/UninitializedSubject.stencil +++ b/stencils/UninitializedSubject.stencil @@ -22,6 +22,7 @@ class UninitializedSubject: ObservableOb toMapper: @escaping (Input?) -> Output?, fromMapper: @escaping (Output?) -> Input? ) { + assert(Thread.isMainThread, "Constructor must be called on the main thread, but called on \(Thread.current)") input = subject.currentOrNull if input != nil { value = toMapper(input!) @@ -65,7 +66,10 @@ class UninitializedSubject: ObservableOb } deinit { - disposeBag.dispose() + let bag = disposeBag + DispatchQueue.main.async { + bag.dispose() + } } }