user2082485
user2082485

Reputation:

RxSwift `.addDisposableTo(disposeBag)` causes memory leak

I am using heavily in my companies project RxSwift. And when running performance tests in Instrument really worrying problem appeared.

Each time .addDisposableTo(disposeBag) gets called, Instruments show up memory leak around 10 bytes. There's no specific pattern of why it would happen, like not using [weak self] in right places, it just happens for no apparent reason.

Some sample code:

class ContactsViewModel: NSObject {
    fileprivate let disposeBag = DisposeBag()
    fileprivate let provider = AuthorizedNetworking().provider

    var contacts: Variable<[User]> = Variable([])
    var suggestedContacts: Variable<[User]> = Variable([])

    func fetchContact(suggestions: Bool = false) {
        ActivityIndicator.showLoadingHUD(message: "Fetching contacts...")
        let observable = provider.request(suggestions ?
            .suggest :
            .searchContacts(query: nil, global: false)).filterSuccessfulStatusCodes()
        let mapped = observable.checkForErrors().mapObject(DataListResponse<User>.self)
        mapped.subscribe { [weak self] event in
            switch event {
            case let .next(response):
                ActivityIndicator.hideLoadingHUD()
                if response.success, let contacts = response.data {
                    if suggestions {
                        self?.suggestedContacts.value = contacts
                    } else {
                        self?.contacts.value = contacts.filter { $0.contactType == "Friend" }
                    }
                } else {
                    Log(.Network, .Error, "Unable to retrieve current user")
                }
            case let .error(error):
                ActivityIndicator.hideLoadingHUD()
                Log(.Network, .Error, error.localizedDescription)
            default:
                break
            }
            }.addDisposableTo(disposeBag) <- Instruments show leak [6 bytes] at this line

    }
}

I've done some research and I have one version that Instrument might not understand RxSwift and make it look like there's leak but in reality, there isn't. But most likely my implementation has problems that I don't know of since I have little experience in RxSwift. Any help appreciated.

Upvotes: 1

Views: 835

Answers (1)

XME
XME

Reputation: 525

I would get a second opinion using RxSwift resource debugging features. You can debug memory leaks using the RxSwift.Resources.total variable to be sure that the problem is RxSwift and not a false positive of Instruments.

Enable debug mode as explained in RxSwift issue #378, add this code to your app delegate:

/* add somewhere in
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil)
*/
_ = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
    .subscribe(onNext: { _ in
        print("Resource count \(RxSwift.Resources.total)")
    })

and use several times your observables to see if the total number of resources is always the same at the end of the process.

Finally, take into account that if the object that contains the observable or the dispose bag is leaked, the problem is the container object, not observables. I was leaking a view and a controller due to a problem with Facebook SDK, and I found the issue when debugging the observables used inside the controller :) .

I hope it helps, Xavi

Upvotes: 2

Related Questions