繁体   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