這是我向 StackOverflow 社區提出的第一個問題,如果我做錯了什么,請見諒。
1.我想要實作的目標
基本上,我想在 Eureka 的SelectableSection類周圍制作一個自定義的反應式包裝器,以便在更改時觀察所選行的值。我想從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()
}
}
}
}
任何幫助將不勝感激,謝謝。??
uj5u.com熱心網友回復:
這里的基本問題是SelectableSectionType協議不限于型別別并Reactive假定它Base是一個類(否則不會被可觀察的創建修改。)
我認為你能做到的最通用的是這樣的:
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,除了最后一次訂閱之外的所有訂閱都將無聲地失敗。解決此問題的簡單方法是始終記住共享任何結果,但這很容易出錯。
解決這個問題的方法是將一個 Subject 與每個 SelectableSection 關聯起來,但是你不能修改這個類,那么我們該怎么辦呢?
這是一個解決方案:
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 時...
- 如果這是第一次使用此部分,它將創建一個主題,并且 RefCountDisposable 分配 onSelectSelectableRow 以向主題發送下一個事件并將主題存盤在陣列中。
- 否則,它將找到與本節相關的主題和一次性用品并保留一次性用品。
一旦它擁有了主題和上面的一次性物件,它將訂閱新的觀察者到主題并回傳一個新的 Disposable,它將洗掉該訂閱并在時間到來時減少參考計數。
是的,這比簡單的賦值案例要復雜得多,但這是正確的做法。
至于呼叫onCompleted()里面的一次性封口。當閉包被呼叫時,觀察者已經發出了一個 onCompleted/onError 事件,或者觀察者已經停止監聽 observable。所以這個事件永遠不會被看到。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/370542.html
