简体   繁体   中英

Transform UIApplicationDelegate methods into RxSwift Observables

In RxSwift / RxCocoa you can create a reactive wrapper for a delegate (eg UIScrollViewDelegate or CLLocationManagerDelegate ) to enable Rx observable sequences for certain delegate methods.

I am trying to implement this for the UIApplicationDelegate method applicationDidBecomeActive:

What I tried so far is pretty straightforward and similar to the DelegateProxy subclasses that are included in RxCocoa.

I created my DelegateProxy subclass:

class RxUIApplicationDelegateProxy: DelegateProxy, UIApplicationDelegate, DelegateProxyType {

    static func currentDelegateFor(object: AnyObject) -> AnyObject? {
        let application: UIApplication = object as! UIApplication
        return application.delegate
    }

    static func setCurrentDelegate(delegate: AnyObject?, toObject object: AnyObject) {
        let application: UIApplication = object as! UIApplication
        application.delegate = delegate as? UIApplicationDelegate
    }
}

And an Rx extension for UIApplication :

extension UIApplication {
    public var rx_delegate: DelegateProxy {
        return proxyForObject(RxUIApplicationDelegateProxy.self, self)
    }

    public var rx_applicationDidBecomeActive: Observable<Void> {
        return rx_delegate.observe("applicationDidBecomeActive:")
            .map { _ in
                return
            }
    }
}

In my AppDelegate I subscribe to the observable:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // the usual setup
    // and then:
    application.rx_applicationDidBecomeActive
        .subscribeNext { _ in
            print("Active!")
        }
        .addDisposableTo(disposeBag)

    return true
}

When I start my app "Active!" gets printed and then I get the following crash in RxCocoa's _RXDelegateProxy_ class:

在此处输入图片说明

Does anybody have an idea what the problem might be? Or has anybody successfully implemented something like rx_applicationDidBecomeActive ?

It looks like a really tricky issue with RxSwift and memory management.

The default implementation of DelegateProxyType sets an instance of a delegate proxy (in this case, RxUIApplicationDelegateProxy ) to the delegate of UIApplication .

It also stores the original AppDelegate as a property called forwardToDelegate so all the delegate methods can still be passed to it.

The problem is that, when the new app delegate is set:

 application.delegate = delegate as? UIApplicationDelegate

the original one is deallocated! You can check it by overriding deinit in AppDelegate . The reasons are explained in this answer . And because the property forwardToDelegate is of type assign , your app crashes as the property points to a deallocated object.

I have found a workaround for that. I'm not really sure if it is a recommended way, so be warned. You can override a method from DelegateProxyType in RxUIApplicationDelegateProxy :

  override func setForwardToDelegate(delegate: AnyObject?, retainDelegate: Bool) {
    super.setForwardToDelegate(delegate, retainDelegate: true)
  }

In normal circumstances, you don't want to retain the delegate as it leads to a retain cycle. But in this special case, this is not a problem: your UIApplication object will exist the entire time while your application is alive anyway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM