2

I have some third party library that has delegate methods. But I like using RX so I should create RxDelegateProxy to receive delegate's callbacks via RX.

Here my custom DelegateProxy class:

extension Reactive where Base:GalleryController {

  var selectedImages:Observable<(GalleryController, [Image])> {
    let proxy = RxGalleryDelegateProxy.createProxy(for: self.base)
    return proxy.imageSubject.asObservable()
  }

}

private class RxGalleryDelegateProxy: DelegateProxy<GalleryController, GalleryControllerDelegate>, DelegateProxyType, GalleryControllerDelegate {

  private var _imageSubject: PublishSubject<(GalleryController, [Image])>?

  public weak fileprivate(set) var galleryController: GalleryController?

  internal var imageSubject: PublishSubject<(GalleryController, [Image])> {
    if let subject = _imageSubject {
      return subject
    }

    let subject = PublishSubject<(GalleryController, [Image])>()
    _imageSubject = subject

    return subject
  }

  static func currentDelegate(for object: GalleryController) -> GalleryControllerDelegate? {
    return object.delegate
  }

  static func setCurrentDelegate(_ delegate: GalleryControllerDelegate?, to object: GalleryController) {
    object.delegate = delegate
  }

  static func registerKnownImplementations() {
    self.register { RxGalleryDelegateProxy(parentObject: $0) }
  }

  private init(parentObject: GalleryController) {
    self.galleryController = castOrFatalError(parentObject)
    super.init(parentObject: parentObject, delegateProxy: RxGalleryDelegateProxy.self)
  }

  func galleryController(_ controller: GalleryController, didSelectImages images: [Image]) {
    if let subject = _imageSubject {
      subject.on(.next((controller, images)))
    }

    self._setForwardToDelegate(galleryController(controller, didSelectImages: images), retainDelegate: true)
  }

  deinit {
    _imageSubject?.on(.completed)
  }

}

In my UIViewController I subscribe with:

final class PhotoLibraryViewController: UIViewController {

  private let _bag = DisposeBag()

  override func viewDidLoad() {
    super.viewDidLoad()

    let gallery = GalleryController()
    present(gallery, animated: true, completion: nil)

    gallery.rx.selectedImages
      .debug("--------")
      .observeOn(MainScheduler.instance)
      .subscribe(onNext: { (controller, images) in
        print("\(images)")
      }, onError: { (error) in
        DDLogError("Error:\n\(error)")
      })
      .disposed(by: _bag)

  }

}

But all I get in console output via .debug("--------") is:

2018-01-09 20:05:14.814: -------- -> subscribed
2018-01-09 20:05:14.817: -------- -> Event completed
2018-01-09 20:05:14.817: -------- -> isDisposed

So my object is immediately disposing just after creation. What did I do wrong?

halfer
  • 19,824
  • 17
  • 99
  • 186
user3742622
  • 1,037
  • 3
  • 22
  • 40

1 Answers1

0

Your gallery object is created inside viewDidLoad(), so once viewDidLoad() is completed, the deinit method from gallery is called and it is disposed.

Move your gallery object out of the viewDidLoad():

final class PhotoLibraryViewController: UIViewController {

  private let _bag = DisposeBag()
  let gallery = GalleryController()

  override func viewDidLoad() {
    super.viewDidLoad()

    present(gallery, animated: true, completion: nil)

    gallery.rx.selectedImages
      .debug("--------")
      .observeOn(MainScheduler.instance)
      .subscribe(onNext: { (controller, images) in
        print("\(images)")
      }, onError: { (error) in
        DDLogError("Error:\n\(error)")
      })
      .disposed(by: _bag)

  }

}
xandrefreire
  • 2,276
  • 14
  • 18
  • This should be correct answer as you are creating the instance of `GalleryController` inside `viewDidLoad` method so once the `viewDidLoad` is completed the instance of `GalleryController` will also deinitialised. – Anirudha Mahale Sep 27 '19 at 06:23