簡體   English   中英

如何在 Eureka SelectableSection 上進行適當的響應式擴展

[英]How to make a proper reactive extension on Eureka SelectableSection

這是我向 StackOverflow 社區提出的第一個問題,如果我做錯了什么,請見諒。

1. 我想要達到的目標
基本上,我想在 Eureka 的SelectableSection class 周圍制作一個自定義反應式包裝器,以便在更改時觀察所選行的值。 我正在考慮從每次選擇一行時調用的onSelectSelectableRow閉包中獲取這些數據。

2. 我為此做了什么
實際上,我已經完成了這項工作,但它不是自定義包裝器的通用用法,這是一個有效的示例,但僅在我指定行及其值類型時才有效,例如ListCheckRow<Int>

extension SelectableSection: ReactiveCompatible {}
extension Reactive where Base : SelectableSection<ListCheckRow<Int>> {
  var selectedValue: Observable<Base.SelectableRow.Cell.Value?> {
    return Observable.create { observer in
      self.base.onSelectSelectableRow = {cell, row in
        observer.onNext(row.value)
      }
      return Disposables.create {
        observer.onCompleted()
      }
    }
  }
}

這工作正常,正如我預期的那樣,但是當涉及到像下一個代碼示例這樣更通用的東西時,我收到一條錯誤消息: “無法分配給屬性:'base' 是 'let' 常量”

extension SelectableSection: ReactiveCompatible {}
extension Reactive where Base : SelectableSectionType {
  var selectedValue: Observable<Base.SelectableRow.Cell.Value?> {
    return Observable.create { observer in
      self.base.onSelectSelectableRow = {cell, row in // Error: Cannot assign to property: 'base' is a 'let' constant
        observer.onNext(row.value)
      }
      return Disposables.create {
        observer.onCompleted()
      }
    }
  }
}

任何幫助將不勝感激,謝謝。

這里的基本問題是SelectableSectionType是一個不限於 class 類型的協議,並且Reactive假定Base是 class (否則不會被可觀察的創建修改。)

我認為你可以做的最通用的是:

extension Reactive {
    func selectedValue<Row, T>() -> Observable<T?> where Base: SelectableSection<Row>, Row: SelectableRowType, T == Row.Cell.Value  {
        Observable.create { [base] observer in
            base.onSelectSelectableRow = { cell, row in
                observer.onNext(row.value) // this is problematic. See below.
            }
            return Disposables.create {
                observer.onCompleted() // this is wrong. See below.
            }
        }
    }
}

上述最大的問題是,如果您多次訂閱生成的 Observable 或使用此計算屬性創建多個 Observable,除了最后一個訂閱之外的所有訂閱都將靜默失敗。 解決此問題的簡單方法是始終記住共享任何結果,但這很容易出錯。

解決這個問題的方法是將一個主題與每個 SelectableSection 相關聯,但是您不能修改 class,那么我們該怎么辦?

這是一個解決方案:

extension Reactive {
    func selectedValue<Row, T>() -> Observable<T?> where Base: SelectableSection<Row>, Row: SelectableRowType, T == Row.Cell.Value  {
        Observable.create { [base] observer in
            if let block = selectableSections.first(where: { $0.section === base }) {
                let subject = block.subject as! PublishSubject<T?>
                return Disposables.create(
                    block.disposable.retain(),
                    subject.subscribe(observer)
                )
            }
            else {
                let subject = PublishSubject<T?>()
                let block = SelectableSectionBlock(
                    section: base,
                    subject: subject,
                    disposable: RefCountDisposable(disposable: Disposables.create {
                        selectableSections.removeAll(where: { $0.section === base })
                    })
                )
                base.onSelectSelectableRow = { cell, row in
                    subject.onNext(row.value)
                }
                selectableSections.append(block)
                return Disposables.create(
                    block.disposable,
                    subject.subscribe(observer)
                )
            }
        }
    }
}

private struct SelectableSectionBlock {
    let section: Section
    let subject: Any
    let disposable: RefCountDisposable
}

private var selectableSections = [SelectableSectionBlock]()

selectableSections數組存儲每個 SelectableSection 的 Subject 和 RefCountDisposable。

每當創建或訂閱 Observable 時...

  • 如果這是第一次使用此部分,它將創建一個 Subject 並 RefCountDisposable 分配 onSelectSelectableRow 以向該主題發送下一個事件並將該主題存儲在數組中。
  • 否則它將找到與本節相關的主題和一次性用品並保留一次性用品。

一旦它從上面獲得了主題和一次性,它將為新的觀察者訂閱主題並返回一個新的 Disposable,它將刪除該訂閱並在時間到來時減少引用計數。

是的,這比簡單的賦值情況要復雜得多,但這是正確的做法。

至於在一次性閉包內調用onCompleted() 在調用閉包時,觀察者已經發出了 onCompleted/onError 事件,或者觀察者已經停止監聽 observable。 所以這個事件永遠不會被看到。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM