Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add withUnretained to SharedSequence #243

Closed
wants to merge 1 commit into from

Conversation

freak4pc
Copy link
Member

@freak4pc freak4pc commented Oct 4, 2019

Based on the request in #242. IRT other traits - there's no real value to add it to Completable... we could add to Maybe and Single in a separate PR.

This PR has a single failing test, I can't really put my finger on what's going on there (the same test passes for Signal but fails for Driver).

If anyone can take a poke at it, that'd be great :)

Thanks !

@freak4pc freak4pc requested review from jdisho and M0rtyMerr October 4, 2019 13:36
@freak4pc freak4pc self-assigned this Oct 4, 2019
public func withUnretained<Object: AnyObject, Out>(_ obj: Object,
resultSelector: @escaping ((Object, Element)) -> Out)
-> SharedSequence<SharingStrategy, Out> {
asObservable()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm casting back and forth to be able to throw a sequence-terminating error. The original implementation used a flatMap but that would be tricky given a completion doesn't affect the upstream.

Copy link
Member

@M0rtyMerr M0rtyMerr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really strange case about failing test case. I am interested in resolution of it :)

@@ -42,10 +42,10 @@ extension ObservableType {
- returns: An observable sequence of tuples that contains both an unretained reference on `obj` and the values of the original sequence.
*/
public func withUnretained<Object: AnyObject>(_ obj: Object) -> Observable<(Object, Element)> {
return withUnretained(obj) { ($0, $1) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Package.swift has .v4_2 version. Is it ok to migrate to Swift 5.1 syntax? I think it's better to perform this migration in separate PR for whole repo.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhm yeah, we'll just do the migration in a separate PR.

Once RxSwift 6 is out, it will only support Xcode 11 & Swift 5.1. So we'll release RxSwiftExt 6 accordingly.

import RxTest

class WithUnretainedCocoaTests: XCTestCase {
fileprivate var testClass: TestClass!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: all properties could be private

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point!

@getogrand
Copy link
Member

getogrand commented Dec 20, 2019

I found a bug on this implementation.

In below scenario, the viewModel.estimatedShippingDate is not disposed, so that the viewController and viewModel were not removed in the memory.
I don't really understand why this causes retain cycle nevertheless the self is not referred in the closure body.

The retain cycle is not caused if I change .withUnretained(self) with normal [weak self] capture list.

enum YGShippingType: String, Codable, Comparable, CustomStringConvertible {
  // ...
}

class SomeViewModel {
  private let _estimatedShippingDate = PublishRelay<(Date, YGShippingType)?>()

  // ...

  var estimatedShippingDate: Driver<(Date, YGShippingType)?> {
    _estimatedShippingDate.asDriver(onErrorJustReturn: nil)
      .distinctUntilChanged({
        $0?.0 == $1?.0 && $0?.1 == $1?.1
      })
  }
}

class SomeViewController: UIViewController {
  private let disposeBag = DisposeBag()
  var viewModel: ViewModel! // Injected by swinject

  // ...

  override func viewDidLoad() {
    super.viewDidLoad()
    bindCartTableHeaderView()
  }

  private func bindCartTableHeaderView() {
    // SharedSequence.withUnretained() causes retain cycle
    viewModel.estimatedShippingDate // Driver<(Date, YGShippingType)?>
      .map({ $0 == nil })
      .distinctUntilChanged()
      .withUnretained(self)
      .drive(onNext: { (self, hide) in
        // Note that we did not refer `self`
        print("blabla")
      })
      .disposed(by: disposeBag)

    /* 
    // ObservableType.withUnretained() doesn't cause retain cycle
    viewModel.estimatedShippingDate
      .map({ $0 == nil })
      .distinctUntilChanged()
      .asObservable()
      .withUnretained(self)
      .subscribe(onNext: { (self, hide) in
        print("blabla")
      })
      .disposed(by: disposeBag)
    */
  }
}

@freak4pc freak4pc closed this Nov 20, 2020
@freak4pc freak4pc deleted the branch master November 20, 2020 21:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants