do(onSuccess: print)
?do(onSuccess: Swift.print)
こういうことでしょlet task: Driver<Void> = Observable.just(()) .asDriver { err in print(err) } // drv1 .map { ... } // drv2 .flatMapLatest { ... } //drv3 .map { ... } //drv4
(edited)/* 宣言時 */ func 某Handler(キャプチャリスト相当の引数) -> (Observableから流れてくる型) -> Result { return { (Observableから流れてくる型) in メインの処理をここに書く。Selfはキャプチャされるのがわかりやすい。 } } /* 利用時 */ 川 .flatMap(某Handler(アレ, コレ)) ...
@hiragramobservers.isEmpty? - y -> is first time subscribing? - y -> no reply └ n -> reply latest value <- n ┘
observers.isEmpty? - y -> no reply └ n -> reply latest value
dump()
https://developer.apple.com/documentation/swift/1539127-dump
public class Gen<T, U> {} public typealias IntGen<U> = Gen<Int, U> public typealias IntIntGen = Gen<Int, Int> public protocol Foo { func foo<U>() -> IntGen<U> func bar() -> IntIntGen } class C : Foo { }
do
のonError
とonCompleted
に共通の処理を書きたくない。。。materialze()
を乱用するデメリットありますか?requestStream .do(onSubscribe: { loading = true }, onDispose: { loading = false })
(edited)buttonClickEvent.flatMapLatest { _ in requestStream .do(onSubscribe: { loading = true }, onDispose: { loading = false }) }.disposed(by: bag)
buttonClickEvent.flatMapLatest { _ in requestStream .do(onSubscribe: { loading = true }, onDispose: { loading = false }) }.do(onDispose: { /* ★1 */ }) .disposed(by: bag)
(edited)enum Network<Response> { case loading case loaded(Response) }
API一般はこの型が正しいisLoading
はここから.map { $0 == loading }
だし (edited)response
はここから.flatMap { .from(as? Response) }
で取り出す(enum switch 省略)enum Network<Response> { case loading(Float) case loaded(Response) }
にすれば、進捗も取れるよね (edited)class AAAViewController : UIViewController { public let a: PublishRelay<Void> = .init() public let disposeBag = DisposeBag() func viewDidLoad() { a.flatMapLatest { uself.request() } .subscribe() .disposed(by: disposeBag) } func onButtonClick() { a.accept(()) } private func request() -> Observable<Int> { return Observable<Int>.just(3) .delay(2.0, scheduler: MainScheduler.instance) .do(onSubscribe: { print("subscribe") }, onDispose: { print("dispose") }) } }
a.flatMap { uself.request().take(1) } .subscribe() .disposed(by: disposeBag)
rx.deallocated
つかってflatMapの中で川遊びしてない?on
オペレーターではterminatedとdisposedは分離されてます https://github.com/ReactiveCocoa/ReactiveSwift/blob/bb2a2d6f422f79ebc86a755642ca9bd106578d12/Sources/Signal.swift#L886-L924 (edited)let hoge: Int! = 1 // Int! let fuga = hoge // Int?
var x = relay.value x.mutate() relay.accept(x)
こういうことしてない?let output = Observable.merge(textField.rx.text, vm.text) input.bind { input in Disposables.create( input.bind(to: textField.rx.text), input.bind(to: vm.text) ) }
とりあえずはこれで解決できないかな (edited)// △ button.rx.tap.bind { フラグ箱.accept(!フラグ箱.value) } // ◎ button.rx.tap .withLatest(from: フラグ箱) .map { !$0 } .bind(to: フラグ箱)
って感じです (edited)A.flatMap { x in B.filter(isY).take(1).map{ _ in x } }
だった。flatMapすごい。 (edited)viewDidAppear.flatMapLatest { .combineLatest(animation, network) }
↑やとだめな理由は、networkのキャンセルはしたくないとか?A.withLatestFrom(B.filter(isY)) { x, _ in x }
でどうでしょうか?川 .flatMap { i -> Observable<X> in Observable.create { o in do { let x: X = try doSomething() o.onNext(x) } catch let e { o.onError(e) } return Disposables.create() } .retryWhen { (e: Observable<Error>) -> Observable<X> in e.flatMap { if e.condition { return Observable.error(e) } else { return Observable.just(???) // Xを求められるけど何のために? } } } }
???
の出る幕はないように感じるのですが、何故これが必要なんでしょうか? public func retryWhen<TriggerObservable: ObservableType, Error: Swift.Error>(_ notificationHandler: @escaping (Observable<Error>) -> TriggerObservable) -> Observable<E> { return RetryWhenSequence(sources: InfiniteSequence(repeatedValue: self.asObservable()), notificationHandler: notificationHandler) }
(edited).flatMap { $0 ? .just(()) : .empty() }
.flatMap { .from(optional: f($0)) }
fetchState.flatMap { .from(optional: $0.success) }
fetchState.compactMap { $0.success }
と書けてよろしい。.map { f($0) } . filter { $0 != nil } .map { $0! }
filterNil
がありますねA.filter { !$0.fromUI } .withLatestFrom(state) { (a, state) in state.a = a } .drive(state)
みたいにやればできるな〜と思いました (edited).withLatestFrom(state) { (a, state) in state.a = a }
なるほど、これなら良さそうですねMaybe<T> -> ((T) -> Single<U>) -> Maybe<U>
と、Maybe<T> -> ((T) -> Completable) -> Completable
が足りない気がする (edited).do(onDispose: )
でそのDisposeBagのプロパティをnilにしてみたら、 DisposeBag = nil から突入した doOnDisposeの中で 再度 = nil しようとして、LoE踏んでSimultaneous accessでクラッシュしたObservable<Bool>
↓ ... いろいろなこねこね ↓ bind
↓ AnyObserver<Bool>
/** Abstracts work that needs to be performed on `DispatchQueue.main`. In case `schedule` methods are called from `DispatchQueue.main`, it will perform action immediately without scheduling. This scheduler is usually used to perform UI work. Main scheduler is a specialization of `SerialDispatchQueueScheduler`. This scheduler is optimized for `observeOn` operator. To ensure observable sequence is subscribed on main thread using `subscribeOn` operator please use `ConcurrentMainScheduler` because it is more optimized for that purpose. */
ConcurrentMainScheduler
を使えってことのよう (edited)/** Abstracts work that needs to be performed on `MainThread`. In case `schedule` methods are called from main thread, it will perform action immediately without scheduling. This scheduler is optimized for `subscribeOn` operator. If you want to observe observable sequence elements on main thread using `observeOn` operator, `MainScheduler` is more suitable for that purpose. */
#59 0x000000018e934758 in UIApplicationMain () #60 0x0000000103001330 in main at xxxxxxxxxx #61 0x00000001843a5fc0 in start () Enqueued from com.apple.main-thread (Thread 1) Queue : com.apple.main-thread (serial) #0 0x0000000105de08f4 in _dispatch_queue_push () #1 0x00000001058f9194 in DispatchQueue.async(group:qos:flags:execute:) ()
if DispatchQueue.isMain && currentNumberEnqueued == 1 {
currentNumberEnqueued == 1
これでしょうねMainScheduler : SerialDispatchQueueScheduler
で後者のdocで It is extremely important that this scheduler is serial, because certain operator perform optimizations that rely on that property.
とあって、serialであることが重要なので、すでにキューに積まれているのがある場合はそれを抜かしてメインスレッド上だからといって即時実行することはNG、という感じですかね〜 (edited).subscribeOn(MainScheduler())
guard let weakSelf = self else { return }
or guard let strongSelf = self else { return }
のどちらも見受けられるんですが、strongSelfっておかしくないでしょうか?button .rx.tap.asDriver() .drive(onNext: { [weak self] in guard let weakSelf = self else { return } // or guard let strongSelf = self else { return } // ??? }) .disposed(by: disposeBag)
self
を強参照しているという意味で弱参照の self
に対して strongSelf
と名付けるのは理解できます。self
の名前を変えただけがweakSelf
、そのスコープ内で見る場合は strongSelf
という解釈でしょうか。 self
を強参照しているという意味で弱参照の self
に対して strongSelf と名付ける weakSelf
は 「弱参照型の」という意味で weak var
で使ってます。 「もともと弱参照だった」という意味で、強参照型の変数として使うというコードもあるんですね。 (edited).. { [weak self] in guard let someProperty = self?.someProperty, let someMethod = self?.someMethod, ... else { ... }
こんな感じlet controller = self
とするか、諦めてwself
的なものを使うか、引数でOpitonalを許容してメソッドの中で再度guard で早期リターンですかねえ。要するに私としてはこれでバッチリみたいな答えは持ってないです。if let `self` = self {}
guard let self = self {
でいいんじゃないでしょか。guard let self = self else { return }
の肯定派が多いのか知りたいguard let self = self else
にしていきたいんですけど、なんかトラブルがあるとかいう話をきいてまだ避けています. どんなトラブルだったかは忘れた `self`
だとlldbから見えなくなる、とかだった気がします (edited)if let self = self
はよくなさそうって言ってませんでしたっけ?if let
self = self
` は明文化されていないので使うべきではないという意味でした。if let self = self
が SE-0079 によって公式にサポートされているので、使ってはだめな理由はないと思いますよ。ただ、おもちさんの言っていることも理解できます。 (edited)let self = self
にしたら良いと思いますが、そもそもselfを使わなくてもいいんじゃself
(のプロパティ)をアップデートする場合はどうでしょう? (edited)self?.foo =
ですね。 (edited)?.
が続くより最初に guard
で落としておきたい派ですね。 confirmaOnSubmitButton.rx.tap .subscribe(onNext: { [weak self] _ in self?.isForceValidation = true self?.requestValidation(parameters: parameters) }) .disposed(by: disposeBag)
self
が解放されてるときって、クロージャの中を実行しなくていいケースがほとんどだと思うんですが、 ?.
で無視されるとは言え処理が走ってると思いもよらないコードが走る場合があっていやな感じがするので、盲目的に guard
で脱出させたいです。例外的に、 1 行で済む場合は僕も self?.
使います。... { [weak self] in guard let navigationController = self?.navigationController ... else { .... }
これっすguard
書きたいですね。self?.navigationController
はオプショナルチェインで(.?.?)書いちゃうかな。 confirmaOnSubmitButton.rx.tap .subscribe(onNext: { [weak self] _ in guard let self = self else { return } self.isForceValidation = true self.requestValidation(parameters: parameters) }) .disposed(by: disposeBag)
confirmaOnSubmitButton.rx.tap .subscribe(onNext: { [weak self] _ in guard let weakSelf = self else { return } weakSelf.isForceValidation = true weakSelf.requestValidation(parameters: parameters) }) .disposed(by: disposeBag)
self
が解放されてると実行されないことを明治できると思うんですね。NavigationController?
として取り出したいのでweakSelf
は命名の問題とおもちの言ってるシンタックスハイライトの問題とのバランスだと思っていて、本質的には weakSelf
でも self
でも変わらないと思ってます。let self = self
の左の self
が黒字になってくれれば別にそれで問題がない気がします。weakSelf
は長いので僕は zelf
派でしたが、そこは好みの世界になってしまいそう・・・。let self = self
を使いそうですね。シンタックスハイライトはエディタがイケてないとして我慢。[unowned self]
でも安全じゃないかと思っているのですが、そうでもないんですか?deinit
書いて delegate
を nil
にすれば問題回避できますか?deinit
で必ず切るなら unownded
良さそうな?unowned
を使うのは !
を使うのとかと同じ話だと思っていて、もし nil
で呼ばれることが絶対に起こらないならありだと思います。 (edited)nil
じゃないな。解放されている状態で呼ばれないことが保証されるなら。unowned
使ってますunowned
クラッシュが許容できないのと、 !
でクラッシュが許容できないのは同じ話じゃないですか?!
も同じだと思いますよ。nil
にならないなら !
は積極的に使う派なので、絶対解放されてる状態で呼ばれないなら unowned
は一貫性のある選択になります。!
や unowned
が起こすクラッシュが許容できなくなったら if let
や weak
を優先するのがいいバランスなのかなぁ。array[i]
や i + j
とかも同じ問題を抱えてると思うんですが、これらでクラッシュする確率は相対的に小さいから許容できるということでしょうか?!
や unowned
で良い、UIKit を使ってるとそこの保証が難しく現実的に問題になるケースが多いから [weak self]
を使う、というのは一貫性のある選択ですね。unowned
、そうでないなら weak
という結論になりそう(当たり前だけど)。あとは、クラッシュしたときのリスクと天秤にかけて。使い捨てのスクリプトなら問題ないけど、クラッシュするたびに被るようなアプリとかだと weak
側に傾く。let self =
の問題。 (edited)lazy private(set) var someBinder = Binder<SomeResult>(self) { (controller, someResult) in // ここにNextの処理を書く。 } someResultObservable.bind(to: someBinder).disposed(by: disposeBag)
こうする (edited)someResultObservable.bind(to: Binder(self) { (self, result) in ... }).disposed(by: disposeBag)
someResultObservable.bind(to: Binder(self) { $0.foo($1) }).disposed(by: disposeBag)
someObservable.voidify() : Observable<Void>
みたいなのを自分で書きたくない&管理したくないので、既存のライブラリにあるものを使いたいのですが、ご存知ないでしょうか?.filterNil()
( Observable<Optional<T>>
-> Observable<T>
) みたいなのも探していたのですが、それは RxCommunity のRxOptionalにありました。 func nop<T1>(_: T1) {} func nop<T1, T2>(_: T1, _: T2) {} ...
compactMap
の概念を入れると便利になると思うんですがどうでしょう stream.flatMap { x -> Observable<Foo> in guard x.isValid else { return .error(SomeError()) } guard x.isOnCertainCondition else { return .empty() } return .just(x.foo()) } optionalStream .flatMap(Observable.from(optional:))
いちいちObservableを通すのはソリューションとしてデカすぎると思うんですよね こんなふうに書きたい stream.compactMap { x -> Foo? in guard x.isValid else { throw SomeError() } guard x.isOnCertainCondition else { return nil } return x.foo() } optionalStream .compactMap { $0 }
(edited)must_have_weak_cupture_argument_in_subscribe: name: Must have weak capture argument in Rx#subscribe method match_kinds: - keyword - identifier - typeidentifier - attribute.builtin included: "./(Folio|Redux)/.*\\.swift" regex: rx.tap\s\s*.subscribe\(onNext:\s\{\s(?!\[weak) message: Must have weak capture argument in Rx#subscribe method severity: error
^ これはsubscribeの中はweakキャプチャしなければならない、というルールですが、こんな感じで追加したらいいと思います。/dev/null
のような、何を流しても無視するダミーのObserverを書くことがちょいちょいあるんですが、(主にredなテストを書く時にコンパイル通る状態にするのにつかう) AnyObserver(eventHandler: { _ in })
とか AnyObserver(eventHandler: nop)
とかいちいち書く以外に何かそれ用のものって用意されていたりしませんでしょうか?maybe.asObservable().concat(.just(defaultValue)).take(1).asSingle()
しか思いついてないです。 (edited)@propertyWrapper public struct ObservableProperty<T> { private let relay: BehaviorRelay<T> public var wrappedValue: T { get { return relay.value } set { relay.accept(newValue) } } public var projectedValue: BehaviorRelay<T> { relay } public init(wrappedValue: T) { self.relay = BehaviorRelay(value: wrappedValue) } } public final class ServiceContainer { @ObservableProperty public var style: Style = Style() } func main() { let _ = serviceContainer.$style.subscribe { (style) in apply(style) } }
textViewShouldBeginEditing()
tableView(shouldHighlightRowAt:)
return Observable<[Elements]>.create { observer in let realmElements = realm.objects(Elements.self) observer.onNext(Array(realmElements)) let token = realmElements .observe { result in switch result { case .update(let data, _, _, _): observer.onNext(Array(data)) case .error(let error): observer.onError(error) default: break } } return Disposables.create { token.invalidate() } }
return Observable<[Elements]>.create { observer in observer.onNext(Array(realm.objects(Elements.self))) let token = realm.objects(Elements.self) .observe { result in switch result { case .update(let data, _, _, _): observer.onNext(Array(data)) case .error(let error): observer.onError(error) default: break } } return Disposables.create { token.invalidate() } }
どちらも onNext はちゃんと流れるけど、上だとnextで流れる内容がバグっていることがある、なんでだ (Rx + Realm のはなしreal.objects
の呼び出し回数が違うのも関係あるんかなABCC
の挙動でバグっているのと LLDB 見てもそうだったので.debug
オペレータというのもその手段の一つだねinsert
みたいなAPIがあって、それを呼んでるだけだけど、それがスレッドセーフじゃないとかの線も疑ってる。try realm.add(D)
で追加していますね (edited).subscribe { D in let realm = try Realm() try realm.write { realm.add(D) } }
.subscribe { D in let realm = try Realm() try realm.write { realm.add(D) } }
if isInWriteTransaction { try commitWrite(withoutNotifying: tokens) }
begin_transaction
の先頭に verify_thread
というメソッドの呼び出しがあるので.write
でスレッド違反してればここで引っかかりそうだから、.write
してるところのスレッドは関係ない気がするvoid Realm::verify_thread() const { if (m_scheduler && !m_scheduler->is_on_thread()) throw IncorrectThreadException(); }
return Observable<[Elements]>.create { observer in let realmElements = realm.objects(Elements.self) observer.onNext(Array(realmElements)) let token = realmElements .observe { result in switch result { case .update(let data, _, _, _): observer.onNext(Array(data)) case .error(let error): observer.onError(error) default: break } } return Disposables.create { token.invalidate() } }
return Observable<[Elements]>.create { observer in observer.onNext(Array(realm.objects(Elements.self))) let token = realm.objects(Elements.self) .observe { result in switch result { case .update(let data, _, _, _): observer.onNext(Array(data)) case .error(let error): observer.onError(error) default: break } } return Disposables.create { token.invalidate() } }
どちらも onNext はちゃんと流れるけど、上だとnextで流れる内容がバグっていることがある、なんでだ (Rx + Realm のはなし