Deprecates `Variable` implementing `ObservableType` in favor of `asObservable()`, and changes behavior so it completes the sequence once it is deallocated.
This commit is contained in:
parent
839051fe9b
commit
8b2984e4e2
|
|
@ -700,7 +700,7 @@ This isn't something that should be practiced often, and is a bad code smell, bu
|
|||
|
||||
let kittens = Variable(firstKitten) // again back in Rx monad
|
||||
|
||||
kittens
|
||||
kittens.asObservable()
|
||||
.map { kitten in
|
||||
return kitten.purr()
|
||||
}
|
||||
|
|
@ -873,12 +873,14 @@ Variable wraps a [`Subject`](http://reactivex.io/documentation/subject.html). Mo
|
|||
|
||||
It will also broadcast it's current value immediately on subscription.
|
||||
|
||||
After variable is deallocated, it will complete the observable sequence returned from `.asObservable()`.
|
||||
|
||||
```swift
|
||||
let variable = Variable(0)
|
||||
|
||||
print("Before first subscription ---")
|
||||
|
||||
variable
|
||||
variable.asObservable()
|
||||
.subscribeNext { n in
|
||||
print("First \(n)")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -255,9 +255,10 @@ example("switchLatest") {
|
|||
let var2 = Variable(200)
|
||||
|
||||
// var3 is like an Observable<Observable<Int>>
|
||||
let var3 = Variable(var1)
|
||||
let var3 = Variable(var1.asObservable())
|
||||
|
||||
let d = var3
|
||||
.asObservable()
|
||||
.switchLatest()
|
||||
.subscribe {
|
||||
print($0)
|
||||
|
|
@ -268,7 +269,7 @@ example("switchLatest") {
|
|||
var1.value = 3
|
||||
var1.value = 4
|
||||
|
||||
var3.value = var2
|
||||
var3.value = var2.asObservable()
|
||||
|
||||
var2.value = 201
|
||||
|
||||
|
|
|
|||
|
|
@ -93,10 +93,10 @@ example("BehaviorSubject") {
|
|||
example("Variable") {
|
||||
let disposeBag = DisposeBag()
|
||||
let variable = Variable("z")
|
||||
writeSequenceToConsole("1", sequence: variable).addDisposableTo(disposeBag)
|
||||
writeSequenceToConsole("1", sequence: variable.asObservable()).addDisposableTo(disposeBag)
|
||||
variable.value = "a"
|
||||
variable.value = "b"
|
||||
writeSequenceToConsole("2", sequence: variable).addDisposableTo(disposeBag)
|
||||
writeSequenceToConsole("2", sequence: variable.asObservable()).addDisposableTo(disposeBag)
|
||||
variable.value = "c"
|
||||
variable.value = "d"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ extension Variable {
|
|||
*/
|
||||
@warn_unused_result(message="http://git.io/rxs.uo")
|
||||
public func asDriver() -> Driver<E> {
|
||||
let source = self
|
||||
let source = self.asObservable()
|
||||
.observeOn(driverObserveOnScheduler)
|
||||
return Driver(source)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,39 +45,6 @@ class PartialUpdatesViewController : ViewController {
|
|||
|
||||
var sections = Variable([NumberSection]())
|
||||
|
||||
func skinTableViewDataSource(dataSource: RxTableViewSectionedDataSource<NumberSection>) {
|
||||
dataSource.cellFactory = { (tv, ip, i) in
|
||||
let cell = tv.dequeueReusableCellWithIdentifier("Cell")
|
||||
?? UITableViewCell(style:.Default, reuseIdentifier: "Cell")
|
||||
|
||||
cell.textLabel!.text = "\(i)"
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
dataSource.titleForHeaderInSection = { [unowned dataSource] (section: Int) -> String in
|
||||
return dataSource.sectionAtIndex(section).model
|
||||
}
|
||||
}
|
||||
|
||||
func skinCollectionViewDataSource(dataSource: RxCollectionViewSectionedDataSource<NumberSection>) {
|
||||
dataSource.cellFactory = { (cv, ip, i) in
|
||||
let cell = cv.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: ip) as! NumberCell
|
||||
|
||||
cell.value!.text = "\(i)"
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
dataSource.supplementaryViewFactory = { [unowned dataSource] (cv, kind, ip) in
|
||||
let section = cv.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "Section", forIndexPath: ip) as! NumberSectionView
|
||||
|
||||
section.value!.text = "\(dataSource.sectionAtIndex(ip.section).model)"
|
||||
|
||||
return section
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
|
@ -162,6 +129,39 @@ class PartialUpdatesViewController : ViewController {
|
|||
.addDisposableTo(disposeBag)
|
||||
}
|
||||
|
||||
func skinTableViewDataSource(dataSource: RxTableViewSectionedDataSource<NumberSection>) {
|
||||
dataSource.cellFactory = { (tv, ip, i) in
|
||||
let cell = tv.dequeueReusableCellWithIdentifier("Cell")
|
||||
?? UITableViewCell(style:.Default, reuseIdentifier: "Cell")
|
||||
|
||||
cell.textLabel!.text = "\(i)"
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
dataSource.titleForHeaderInSection = { [unowned dataSource] (section: Int) -> String in
|
||||
return dataSource.sectionAtIndex(section).model
|
||||
}
|
||||
}
|
||||
|
||||
func skinCollectionViewDataSource(dataSource: RxCollectionViewSectionedDataSource<NumberSection>) {
|
||||
dataSource.cellFactory = { (cv, ip, i) in
|
||||
let cell = cv.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: ip) as! NumberCell
|
||||
|
||||
cell.value!.text = "\(i)"
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
dataSource.supplementaryViewFactory = { [unowned dataSource] (cv, kind, ip) in
|
||||
let section = cv.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "Section", forIndexPath: ip) as! NumberSectionView
|
||||
|
||||
section.value!.text = "\(dataSource.sectionAtIndex(ip.section).model)"
|
||||
|
||||
return section
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillDisappear(animated: Bool) {
|
||||
self.timer?.invalidate()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ infix operator <-> {
|
|||
}
|
||||
|
||||
func <-> <T>(property: ControlProperty<T>, variable: Variable<T>) -> Disposable {
|
||||
let bindToUIDisposable = variable
|
||||
let bindToUIDisposable = variable.asObservable()
|
||||
.bindTo(property)
|
||||
let bindToVariable = property
|
||||
.subscribe(onNext: { n in
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class ActivityIndicator : DriverConvertibleType {
|
|||
private let _loading: Driver<Bool>
|
||||
|
||||
init() {
|
||||
_loading = _variable
|
||||
_loading = _variable.asObservable()
|
||||
.map { $0 > 0 }
|
||||
.distinctUntilChanged()
|
||||
.asDriver { (error: ErrorType) -> Driver<Bool> in
|
||||
|
|
|
|||
|
|
@ -11,9 +11,13 @@ import Foundation
|
|||
/**
|
||||
Variable is a wrapper for `BehaviorSubject`.
|
||||
|
||||
Unlike `BehaviorSubject` it can't terminate with error.
|
||||
Unlike `BehaviorSubject` it can't terminate with error, and when variable is deallocated
|
||||
it will complete it's observable sequence (`asObservable`).
|
||||
*/
|
||||
public class Variable<Element> : ObservableType {
|
||||
@available(*, deprecated=2.0.0, message="Variable will remain in the 2.0.0 API, but just use `variable.asObservable()` because it won't be `ObservableType` (no way to warn about deprecated interface implementation). Just do, `variable.asObservable().map { _ in ...}` and ignore this warning.")
|
||||
public class Variable<Element>
|
||||
: ObservableType { // << -- this part and subscribe method will be deprecated
|
||||
|
||||
public typealias E = Element
|
||||
|
||||
private let _subject: BehaviorSubject<Element>
|
||||
|
|
@ -73,4 +77,8 @@ public class Variable<Element> : ObservableType {
|
|||
public func asObservable() -> Observable<E> {
|
||||
return _subject
|
||||
}
|
||||
|
||||
deinit {
|
||||
_subject.on(.Completed)
|
||||
}
|
||||
}
|
||||
|
|
@ -172,7 +172,8 @@ extension ControlTests {
|
|||
// UILabel
|
||||
extension ControlTests {
|
||||
func testLabel_HasWeakReference() {
|
||||
ensureControlObserverHasWeakReference(UILabel(), { (label: UILabel) -> AnyObserver<NSAttributedString?> in label.rx_attributedText }, { Variable<NSAttributedString?>(nil).asObservable() })
|
||||
let variable = Variable<NSAttributedString?>(nil)
|
||||
ensureControlObserverHasWeakReference(UILabel(), { (label: UILabel) -> AnyObserver<NSAttributedString?> in label.rx_attributedText }, { variable.asObservable() })
|
||||
}
|
||||
|
||||
func testLabel_NextElementsSetsValue() {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class ControlTests : RxTest {
|
|||
|
||||
let property = propertySelector(control)
|
||||
|
||||
let disposable = variable.bindTo(property)
|
||||
let disposable = variable.asObservable().bindTo(property)
|
||||
|
||||
_ = property.subscribe(onNext: { n in
|
||||
lastReturnedPropertyValue = n
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class VariableTest : RxTest {
|
|||
let a = Variable(1)
|
||||
let b = Variable(2)
|
||||
|
||||
let c = Observable.combineLatest(a, b, resultSelector: +)
|
||||
let c = Observable.combineLatest(a.asObservable(), b.asObservable(), resultSelector: +)
|
||||
|
||||
var latestValue: Int?
|
||||
|
||||
|
|
@ -41,6 +41,26 @@ class VariableTest : RxTest {
|
|||
XCTAssertEqual(latestValue!, 14)
|
||||
}
|
||||
|
||||
func testVariable_sendsCompletedOnDealloc() {
|
||||
var a = Variable(1)
|
||||
|
||||
var latest = 0
|
||||
var completed = false
|
||||
a.asObservable().subscribe(onNext: { n in
|
||||
latest = n
|
||||
}, onCompleted: {
|
||||
completed = true
|
||||
})
|
||||
|
||||
XCTAssertEqual(latest, 1)
|
||||
XCTAssertFalse(completed)
|
||||
|
||||
a = Variable(2)
|
||||
|
||||
XCTAssertEqual(latest, 1)
|
||||
XCTAssertTrue(completed)
|
||||
}
|
||||
|
||||
func testVariable_READMEExample() {
|
||||
|
||||
// Two simple Rx variables
|
||||
|
|
@ -49,7 +69,7 @@ class VariableTest : RxTest {
|
|||
let b /*: Observable<Int>*/ = Variable(2)
|
||||
|
||||
// Computed third variable (or sequence)
|
||||
let c /*: Observable<Int>*/ = Observable.combineLatest(a, b) { $0 + $1 }
|
||||
let c /*: Observable<Int>*/ = Observable.combineLatest(a.asObservable(), b.asObservable()) { $0 + $1 }
|
||||
|
||||
// Reading elements from c.
|
||||
// This is just a demo example.
|
||||
|
|
|
|||
Loading…
Reference in New Issue