smandrus
smandrus

Reputation: 335

RxSwift: Is it safe to always use [unowned self] when a class has a disposeBag property?

I recently found an article that says using [unowned self] is always safe as long as you are adding the subscription to a DisposeBag and it is inside the view controller.

Assuming I have a ViewController where deinit is not being called due to a strong reference:

class ViewController: UIViewController {

    @IBOutlet weak var searchBar: UISearchBar!
    @IBOutlet weak var tableView: UITableView!

    private let disposeBag = DisposeBag()
    private var results = Variable<[Item]>([])
    private var searchText = Variable("")
    var selectedCompletion: ((Item) -> Void)!

    override func viewDidLoad() {
        super.viewDidLoad()
        results.asObservable()
            .bind(to: tableView.rx.items(cellIdentifier: "CustomCell", cellType: CustomCell.self)) { row, item, cell in
                cell.configure(with: item)
            }
            .disposed(by: disposeBag)

        tableView.rx.itemSelected
            .subscribe(onNext: { ip in
                self.selectedCompletion(self.results.value[ip.row])
                self.navigationController?.popViewController(animated: true)
            })
            .disposed(by:disposeBag)

        searchBar.rx.text
            .debounce(0.6, scheduler: MainScheduler.instance)
            .subscribe(onNext: { searchText in
                if searchText == nil || searchText!.isEmpty { return }
                self.search(query: searchText!)
            })
            .disposed(by: disposeBag)
    }

    private func search(query: String) {
        // Search asynchronously
        search(for: query) { response in

            // Some logic here...
            self.results.value = searchResult.results
        }
    }
}

I should simply be able to declare [unowned self] in my subscription closures and not have to worry about my app crashing from self being nil.

Where I'm confused is, because search is asynchronous, doesn't that mean self can be nil if the ViewController has been popped off the navigation stack before the query completes?

Or would the disposeBag be deallocated first and the closure wouldn't complete?

Any clarification about how to know whether or not a class owns a closure would be great too.

Upvotes: 4

Views: 2540

Answers (2)

Constantine Fry
Constantine Fry

Reputation: 432

as @kzaher says on github

you should never use unowned.

sources:

https://github.com/RxSwiftCommunity/RxDataSources/issues/169 https://github.com/ReactiveX/RxSwift/issues/1593

Upvotes: 0

Nikita Ermolenko
Nikita Ermolenko

Reputation: 2259

In my experience it's a safe approach to use unowned with a dispose bag, except one block - onDisposed. There have been the cases when an app crashed because of unowed keyword -> weak is useful here.

Upvotes: 1

Related Questions