如何取消订阅观察?

时间:2016-09-12 20:20:10

标签: swift rx-swift

如果我的内容如下:

  func foo() -> Observable<Foo> {
    return Observable.create { observer in
      // ...
    }
  }

  func bar() {
    foo().observeOn(MainScheduler.instance)
      .subscribeNext {
        // ...
      }
      .addDisposableTo(disposeBag)
  }

如果我想稍后在bar中观察到unsubscribe,我该怎么做?

更新

我知道我可以致电dispose,但根据RxSwift docs

  

请注意,您通常不希望手动调用dispose;这只是教育的例子。手动调用处理通常是一种糟糕的代码味道。

unsubscribe刚刚没有实现?我已经完成了对RxSwift代码的探索,并且在某种程度上我可以理解发生了什么,它看起来不像从订阅方法返回的Disposable是任何具有有用功能的东西(除了处置)。

5 个答案:

答案 0 :(得分:3)

您将Observable返回的foo添加到disposeBag。它在取消分配时处理订阅。 你可以手动&#34;通过调用

释放disposeBag

disposeBag = nil

你班上的某个地方。

问题编辑后:您希望有选择地取消订阅某些Observable,可能是在满足某些条件时。您可以使用代表这些条件的其他Observable,并根据需要使用takeUntil运算符取消订阅。

//given that cancellingObservable sends `next` value when the subscription to `foo` is no longer needed

foo().observeOn(MainScheduler.instance)
  .takeUntil(cancellingObservable)
  .subscribeNext {
    // ...
  }
  .addDisposableTo(disposeBag)

答案 1 :(得分:1)

由于以上回答的重点是取消订阅特定或特定的可观察对象,因此我将讨论正确,有效地一起取消订阅所有可观察对象。

如何订阅

this.myVariable$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(value => {
  // Do the thing you want to do after there is change in myVariable
});

如何退订

ngOnDestroy() {
  this.ngUnsubscribe.next();
  this.ngUnsubscribe.complete();
}

使用以上ngOnDestroy,您可以取消所有可观察的订阅。

答案 2 :(得分:1)

详细信息

  • Xcode版本11.0(11A420a),iOS 13,Swift 5
  • RxSwift v 5.0.1

解决方案

如果您想取消订阅可观察的项目,只需重置disposeBag

// Way 1
private lazy var disposeBag = DisposeBag()

//...
disposeBag = DisposeBag()

// Way 2
private lazy var disposeBag: DisposeBag? = DisposeBag()

//...
disposeBag = nil

完整样本

import UIKit
import RxSwift

class Service {
    private lazy var publishSubject = BehaviorSubject<Int>(value: count)
    private lazy var count = 0
    var counter: Observable<Int>  { publishSubject }
    func unsubscribeAll() { publishSubject.dispose() }
    func increaseCounter() {
        count += 1
        publishSubject.onNext(count)
    }
}

class ViewController: UIViewController {

    private lazy var service = Service()
    private lazy var disposeBag = DisposeBag()
    private weak var navigationBar: UINavigationBar!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupNavigationBar()
        subscribeToObservables()
    }
}

// MARK: Work with subviews

extension ViewController {

    private func setupNavigationBar() {
        let navigationBar = UINavigationBar()
        view.addSubview(navigationBar)
        navigationBar.translatesAutoresizingMaskIntoConstraints = false
        navigationBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        navigationBar.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
        navigationBar.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true

        let navigationItem = UINavigationItem()
        var barButtons = [UIBarButtonItem]()
        barButtons.append(createNavigationItemButton(title: "subscr.", action: #selector(subscribeButtonTapped)))
        barButtons.append(createNavigationItemButton(title: "unsubscr.", action: #selector(unsubscribeButtonTapped)))
        navigationItem.leftBarButtonItems = barButtons
        navigationItem.rightBarButtonItem = createNavigationItemButton(title: "+", action: #selector(increaseCounterNavigationItemButtonTapped))
        navigationBar.items = [navigationItem]
        self.navigationBar = navigationBar
    }

    private func createNavigationItemButton(title: String, action: Selector?) -> UIBarButtonItem {
        return UIBarButtonItem(title: title, style: .plain, target: self, action: action)
    }

}

// MARK: Work with observers

extension ViewController {
    private func subscribeToObservables() {
        service.counter.subscribe { [weak self] value in
            guard   let value = value.element,
                    let navigationItem = self?.navigationBar?.items?.first else { return }
            navigationItem.title = "Counter \(value)"
            print(value)
        }.disposed(by: disposeBag)

    }

    private func unsubscribeFromObservables() { disposeBag = DisposeBag() }
}

// MARK: Button actions

extension ViewController {
    @objc func increaseCounterNavigationItemButtonTapped(_ source: UIBarButtonItem) { service.increaseCounter() }
    @objc func subscribeButtonTapped(_ source: UIBarButtonItem) { subscribeToObservables() }
    @objc func unsubscribeButtonTapped(_ source: UIBarButtonItem) { unsubscribeFromObservables() }
}

示例应用的屏幕截图

enter image description here

答案 3 :(得分:0)

您可以使用一个新的覆盖disposeBag。如果您需要其他可观察的物体来保持生命,请创建多个disposeBags。如果您考虑一下,这是当一个类被释放时发生的事情→它的disposeBag被释放,释放该类拥有的所有订阅。

示例:

注意:该示例仅说明了原理,我不知道您为什么会像下面这样专门构建某些内容。话虽如此,根据您的体系结构,使用prepareForReuse清除单元格可能会很有趣。

class MyClass {

   var clearableDisposeBag = DisposeBag()
   let disposeBag = DisposeBag()

   let dependencies: Dependencies
   let myObservable: MyObservable

   var myOtherObservable: MyOtherObservable?

   init(dependencies: Dependencies) {
      self.dependencies = dependencies
      self.myObservable = dependencies
         .myObservable
         .subscribe(onNext: doSomething)
         .disposed(by: disposeBag)
   }

   private func doSomething() {/*...*/}

   private func doSomethingElse() {/*...*/}

   private func subscribeToChanges() {
      /// clear previous subscription
      clearableDisposeBag = DisposeBag()
      /// subscribe again
      myOtherObservable = dependencies
         .myOtherObservable
         .subscribe(onNext: doSomethingElse)
         .disposed(by: clearableDisposeBag)
   }
}

答案 4 :(得分:-1)

我所做的是创建另一个DisposeBag

var tempBag = DisposeBag()

fun bar() {
    foo().subscribe().addDisposable(tempBag)
}

因此,当您想要处置时,您可以在要发布时执行tempBag = nil。而你还有另一个DisposeBag让其他一次性用品活着。