RxSwift(4) 练习
经过了几天的学习,边看文档边敲代码,顺便把一些代码记录下来,以备后面温习。
先看一个delay函数
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
concat
*在已有的sequence 中加入另外一个sequence *
let a = Variable(1)
let b = Variable(2)
// let d = Variable(100)
let f = Variable("sun->concat")
_ = Observable.combineLatest(a.asObservable(), b.asObservable()) { (intA, IntB) -> Int in
print("......1 ...>>= \\(intA ) b= \\(IntB)")
return intA + IntB
}.map { (intAB) -> String in
print("......2")
return String(intAB)
}.concat(f.asObservable())// map 返回String,这里使用a,b 就不行
.filter { (str) -> Bool in
print("......3")
return str.characters.count > 0
}.subscribeNext { (value) -> Void in
print("......4")
print("value ==== \\(value)")
}
输出如下:
......1 ...>>= 1 b= 2
......2
......3
......4
value ==== 3
这里concat 还没有emit 任何的item 所以不会触发print
但是由于a,b 都已经有了初始值所以只要subscribe 就会执行print
map ,filter 操作都会执行。如果是concat 生成的observable 触发的操作只执行后面的filter
再看另外一个操作
a.value = 100
delay(2) { () -> () in
print("after 2 second...")
f.value = "sunjianfeng"
}
这样的输出如下:
......1 ...>>= 1 b= 2
......2
......3
......4
value ==== 3
......1 ...>>= 100 b= 2
......2
......3
......4
value ==== 102
......3
......4
value ==== sun->concat
after 2 second...
......3
......4
value ==== sunjianfeng
注意如果仅仅是 a.value = 100 没有delay的操作,仅仅会执行a,b的输入输出.
总结: 对生成的observable 进行的操作如同一个管道一样,都会按顺序执行
combinlatest-observable->map->filter->print
concat-Observable->filter->print
Dispose
每一个subscriber 一旦subscription 就会生成一个单独的元素序列,我们定义的Observable的操作函数(
operator
) 一般是无状态的,只有subscribe 后才会变成有状态的(大多数的操作函数是无状态的)
我们先定义了一个operator
(myInterval),返回一个匿名的Dispose,当我们手动dispose 后改计数器停止工作。
func myInterval (interval:NSTimeInterval)-> Observable<Int>{
return Observable.create({ (observer) -> Disposable in
print("Subscribed")
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
let timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0,0,queue);
var next = 0;
dispatch_source_set_timer(timer, 0, UInt64(interval * Double(NSEC_PER_SEC)), 0)
let cancel = AnonymousDisposable {
print("Disposed")
dispatch_source_cancel(timer)
}
dispatch_source_set_event_handler(timer, {
if cancel.disposed {
return
}
observer.on(.Next(next))
next += 1
})
dispatch_resume(timer)
return cancel
})
}
先尝试一下这个, 指定1秒间隔,5秒后停止
let counter = myInterval(1);
print("started .....")
let subscription = counter.subscribeNext { (n) -> Void in
print(n)
}
NSThread.sleepForTimeInterval(5)
subscription.dispose()
print("end ....")
输出:
started .....
Subscribed
0
1
2
3
4
Disposed
end ....
再改一下,订阅两次
func testMyInterval2(){
let counter = myInterval(0.1)
print("Started ----")
let subscription1 = counter
.subscribeNext { n in
print("First \\(n)")
}
let subscription2 = counter
.subscribeNext { n in
print("Second \\(n)")
}
NSThread.sleepForTimeInterval(0.5)
subscription1.dispose()
NSThread.sleepForTimeInterval(0.5)
subscription2.dispose()
print("Ended ----")
}
输出:
/**
Started ----
Subscribed
Subscribed
First 0
Second 0
First 1
Second 1
Second 2
First 2
Second 3
First 3
Second 4
First 4
Disposed
这是第二个
Second 5
Second 6
Second 7
Second 8
Second 9
Disposed
Ended ----
*/
这说明每一个subscribe后都会生成一个单独的sequence
自定义 函数
func myJust<E>(element:E)-> Observable<E> {
return Observable.create({ (observer) -> Disposable in
observer.on(Event.Next(element))
observer.on(.Completed);
return NopDisposable.instance;
})
}
myJust(0)
.subscribeNext { n in
print(n)
}
sharing Subscription and shareReplay
operator
let counter = myInterval(0.1)
.shareReplay(1)
print("Started ----")
let subscription1 = counter
.subscribeNext { n in
print("First \\(n) ")
}
let subscription2 = counter
.subscribeNext { n in
print("Second \\(n) ")
}
NSThread.sleepForTimeInterval(0.5)
subscription1.dispose()
NSThread.sleepForTimeInterval(0.5)
subscription2.dispose()
print("Ended ----")
/**
Started ----
Subscribed
First 0
Second 0
First 1
Second 1
First 2
Second 2
First 3
Second 3
First 4
Second 4
Second 5
Second 6
Second 7
Second 8
Second 9
Disposed
Ended ----
一个disposed
自定义operator
extension ObservableType{
func myMap<R>(transformK :E -> R)-> Observable<R>{
return Observable.create { (observer) -> Disposable in
let subscription = self.subscribe
{ (event) -> Void in
switch event{
case .Next(let value):
let result = transformK(value)
observer.on(.Next(result))
case .Error (let error):
observer.on(.Error(error))
case .Completed :
observer.on(.Completed)
}
}
return subscription
}
}
}
/*
let subscription = myInterval(0.1)
.myMap { e in
return "This is simply \\(e)"
}
.subscribeNext { n in
print(n)
}
*/
Debugging memory leaks
In debug mode Rx tracks all allocated resources in a global variable resourceCount
.In case you want to have some resource leak detection logic, the simplest method is just printing out RxSwift.resourceCount
periodically to output.
/* add somewhere infunc application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool*/
_ = Observable<Int>.interval(1, scheduler: MainScheduler.instance) .subscribeNext { _ in print("Resource count \\(RxSwift.resourceCount)")
}
Most efficient way to test for memory leaks is:
- navigate to your screen and use it
- navigate back
- observe initial resource count
- navigate second time to your screen and use it
- navigate back
- observe final resource countIn case there is a difference in resource count between initial and final resource counts, there might be a memoryleak somewhere.
The reason why 2 navigations are suggested is because first navigation forces loading of lazy resources.