| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- //
- // SignalLifetimeSpec.swift
- // ReactiveCocoa
- //
- // Created by Vadim Yelagin on 2015-12-13.
- // Copyright (c) 2015 GitHub. All rights reserved.
- //
- import Result
- import Nimble
- import Quick
- import ReactiveCocoa
- class SignalLifetimeSpec: QuickSpec {
- override func spec() {
- describe("init") {
- var testScheduler: TestScheduler!
- beforeEach {
- testScheduler = TestScheduler()
- }
- it("should deallocate") {
- weak var signal: Signal<AnyObject, NoError>? = Signal { _ in nil }
- expect(signal).to(beNil())
- }
- it("should deallocate even if it has an observer") {
- weak var signal: Signal<AnyObject, NoError>? = {
- let signal: Signal<AnyObject, NoError> = Signal { _ in nil }
- return signal
- }()
- expect(signal).to(beNil())
- }
- it("should deallocate even if it has an observer with retained disposable") {
- var disposable: Disposable? = nil
- weak var signal: Signal<AnyObject, NoError>? = {
- let signal: Signal<AnyObject, NoError> = Signal { _ in nil }
- disposable = signal.observe(Observer())
- return signal
- }()
- expect(signal).to(beNil())
- disposable?.dispose()
- expect(signal).to(beNil())
- }
- it("should deallocate after erroring") {
- weak var signal: Signal<AnyObject, TestError>? = Signal { observer in
- testScheduler.schedule {
- observer.sendFailed(TestError.Default)
- }
- return nil
- }
- var errored = false
- signal?.observeFailed { _ in errored = true }
- expect(errored) == false
- expect(signal).toNot(beNil())
- testScheduler.run()
- expect(errored) == true
- expect(signal).to(beNil())
- }
- it("should deallocate after completing") {
- weak var signal: Signal<AnyObject, NoError>? = Signal { observer in
- testScheduler.schedule {
- observer.sendCompleted()
- }
- return nil
- }
- var completed = false
- signal?.observeCompleted { completed = true }
- expect(completed) == false
- expect(signal).toNot(beNil())
- testScheduler.run()
- expect(completed) == true
- expect(signal).to(beNil())
- }
- it("should deallocate after interrupting") {
- weak var signal: Signal<AnyObject, NoError>? = Signal { observer in
- testScheduler.schedule {
- observer.sendInterrupted()
- }
- return nil
- }
- var interrupted = false
- signal?.observeInterrupted {
- interrupted = true
- }
- expect(interrupted) == false
- expect(signal).toNot(beNil())
- testScheduler.run()
- expect(interrupted) == true
- expect(signal).to(beNil())
- }
- }
- describe("Signal.pipe") {
- it("should deallocate") {
- weak var signal = Signal<(), NoError>.pipe().0
- expect(signal).to(beNil())
- }
- it("should deallocate after erroring") {
- let testScheduler = TestScheduler()
- weak var weakSignal: Signal<(), TestError>?
- // Use an inner closure to help ARC deallocate things as we
- // expect.
- let test = {
- let (signal, observer) = Signal<(), TestError>.pipe()
- weakSignal = signal
- testScheduler.schedule {
- observer.sendFailed(TestError.Default)
- }
- }
- test()
- expect(weakSignal).toNot(beNil())
- testScheduler.run()
- expect(weakSignal).to(beNil())
- }
- it("should deallocate after completing") {
- let testScheduler = TestScheduler()
- weak var weakSignal: Signal<(), TestError>?
- // Use an inner closure to help ARC deallocate things as we
- // expect.
- let test = {
- let (signal, observer) = Signal<(), TestError>.pipe()
- weakSignal = signal
- testScheduler.schedule {
- observer.sendCompleted()
- }
- }
- test()
- expect(weakSignal).toNot(beNil())
- testScheduler.run()
- expect(weakSignal).to(beNil())
- }
- it("should deallocate after interrupting") {
- let testScheduler = TestScheduler()
- weak var weakSignal: Signal<(), NoError>?
- let test = {
- let (signal, observer) = Signal<(), NoError>.pipe()
- weakSignal = signal
- testScheduler.schedule {
- observer.sendInterrupted()
- }
- }
- test()
- expect(weakSignal).toNot(beNil())
- testScheduler.run()
- expect(weakSignal).to(beNil())
- }
- }
- describe("testTransform") {
- it("should deallocate") {
- weak var signal: Signal<AnyObject, NoError>? = Signal { _ in nil }.testTransform()
- expect(signal).to(beNil())
- }
- it("should deallocate even if it has an observer") {
- weak var signal: Signal<AnyObject, NoError>? = {
- let signal: Signal<AnyObject, NoError> = Signal { _ in nil }.testTransform()
- signal.observe(Observer())
- return signal
- }()
- expect(signal).to(beNil())
- }
- it("should deallocate even if it has an observer with retained disposable") {
- var disposable: Disposable? = nil
- weak var signal: Signal<AnyObject, NoError>? = {
- let signal: Signal<AnyObject, NoError> = Signal { _ in nil }.testTransform()
- disposable = signal.observe(Observer())
- return signal
- }()
- expect(signal).to(beNil())
- disposable?.dispose()
- expect(signal).to(beNil())
- }
- }
- describe("observe") {
- var signal: Signal<Int, TestError>!
- var observer: Signal<Int, TestError>.Observer!
- var token: NSObject? = nil
- weak var weakToken: NSObject?
- func expectTokenNotDeallocated() {
- expect(weakToken).toNot(beNil())
- }
- func expectTokenDeallocated() {
- expect(weakToken).to(beNil())
- }
- beforeEach {
- let (signalTemp, observerTemp) = Signal<Int, TestError>.pipe()
- signal = signalTemp
- observer = observerTemp
- token = NSObject()
- weakToken = token
- signal.observe { [token = token] _ in
- _ = token!.description
- }
- }
- it("should deallocate observe handler when signal completes") {
- expectTokenNotDeallocated()
- observer.sendNext(1)
- expectTokenNotDeallocated()
- token = nil
- expectTokenNotDeallocated()
- observer.sendNext(2)
- expectTokenNotDeallocated()
- observer.sendCompleted()
- expectTokenDeallocated()
- }
- it("should deallocate observe handler when signal fails") {
- expectTokenNotDeallocated()
- observer.sendNext(1)
- expectTokenNotDeallocated()
- token = nil
- expectTokenNotDeallocated()
- observer.sendNext(2)
- expectTokenNotDeallocated()
- observer.sendFailed(.Default)
- expectTokenDeallocated()
- }
- }
- }
- }
- private extension SignalType {
- func testTransform() -> Signal<Value, Error> {
- return Signal { observer in
- return self.observe(observer.action)
- }
- }
- }
|