如何在 Eureka SelectableSection 上进行适当的响应式扩展
How to make a proper reactive extension on Eureka SelectableSection
这是我向 Whosebug 社区提出的第一个问题,如果我做错了什么,请原谅。
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 关联一个 Subject,但是您不能修改 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: { [=11=].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: { [=11=].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 时...
- 如果这是第一次使用此部分,它将创建一个主题并 RefCountDisposable 分配 onSelectSelectableRow 以将下一个事件发送到主题并将主题存储在数组中。
- 否则会找到与该Section关联的subject和disposable,并保留disposable。
一旦它从上面获得了主题和一次性,它将订阅新的观察者到主题和 return 一个新的 Disposable,它将在时机成熟时删除该订阅并减少引用计数。
是的,这比简单的赋值案例要复杂得多,但这是正确的做法。
至于调用onCompleted()
一次性闭包。在调用闭包时,观察者已经发出了一个 onCompleted/onError 事件,或者观察者已经停止监听可观察对象。所以这个事件永远不会被看到。
这是我向 Whosebug 社区提出的第一个问题,如果我做错了什么,请原谅。
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 关联一个 Subject,但是您不能修改 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: { [=11=].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: { [=11=].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 时...
- 如果这是第一次使用此部分,它将创建一个主题并 RefCountDisposable 分配 onSelectSelectableRow 以将下一个事件发送到主题并将主题存储在数组中。
- 否则会找到与该Section关联的subject和disposable,并保留disposable。
一旦它从上面获得了主题和一次性,它将订阅新的观察者到主题和 return 一个新的 Disposable,它将在时机成熟时删除该订阅并减少引用计数。
是的,这比简单的赋值案例要复杂得多,但这是正确的做法。
至于调用onCompleted()
一次性闭包。在调用闭包时,观察者已经发出了一个 onCompleted/onError 事件,或者观察者已经停止监听可观察对象。所以这个事件永远不会被看到。