Skip to content

Dwifft -> DifferenceKit #136

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

Merged
merged 8 commits into from
Sep 11, 2018
Merged

Dwifft -> DifferenceKit #136

merged 8 commits into from
Sep 11, 2018

Conversation

benasher44
Copy link
Contributor

@benasher44 benasher44 commented Aug 20, 2018

Changes in this pull request

This swaps out Dwifft for DifferenceKit, which uses Paul Heckel's more efficient diffing algo (same one used by IGListKit). Most of the work here is adding layers to avoid Self/associatedtype requirements issues with our protocols. These layers could be removed in the future though, pending changes that would allow this in Swift 5 or generics changes to TableViewModel/CollectionViewModel.

This also fixes #126

Checklist

  • All tests pass. Demo project builds and runs.
  • I added tests, an experiment, or detailed why my change isn't tested.
  • I added an entry to the CHANGELOG.md for any breaking changes, enhancements, or bug fixes.
  • I have reviewed the contributing guide

@benasher44 benasher44 added this to the 0.2.0 milestone Aug 20, 2018
@benasher44
Copy link
Contributor Author

Preliminary tests using this with problem projects in PG look really good. Going to hold off putting in more effort here, until we can do more thorough testing internally.

/// Creates a type-erased Differentiable for DiffableViewModel.
/// These are only created internally from either `TableCellViewModel` or `CollectionCellViewModel`,
/// so that we can safely force cast the models back to those types.
public struct AnyDiffableViewModel {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can some of these helper types be made non-public?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope. They're used in public methods/vars that are requirements of public protocols.

Copy link
Contributor

Choose a reason for hiding this comment

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

If this struct is only used internally, can it be internal instead of public?

Maybe I'm misreading your comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

AnyDiffableViewModel is used in a decl that satisfies a protocol for a public type, so this has to be public.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, got it 👍

@benasher44 benasher44 force-pushed the basher/differencekit branch from da98482 to 6d24e30 Compare August 24, 2018 17:08
Copy link
Contributor

@jessesquires jessesquires left a comment

Choose a reason for hiding this comment

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

Overall looks good! 💯

}
self.refreshViews()
Copy link
Contributor

Choose a reason for hiding this comment

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

👌 Looks much cleaner

/// Creates a type-erased Differentiable for DiffableViewModel.
/// These are only created internally from either `TableCellViewModel` or `CollectionCellViewModel`,
/// so that we can safely force cast the models back to those types.
public struct AnyDiffableViewModel {
Copy link
Contributor

Choose a reason for hiding this comment

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

If this struct is only used internally, can it be internal instead of public?

Maybe I'm misreading your comment?

diffingKey: sectionModel.diffingKey
)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🎉


/// MARK: - DifferenceKit Protocol Conformance

extension TableSectionViewModel: DifferentiableSection {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jessesquires AnyDiffableViewModel is used to satisfy the DifferentiableSection protocol. Because TableSectionViewModel is public, this protocol implementation must be made public (and cascades back to AnyDiffableViewModel)

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, got it 👍

@jessesquires
Copy link
Contributor

I'm assuming this fixes #126 ?

@benasher44
Copy link
Contributor Author

@jessesquires possibly? TBH, I can't tell what should be broken about UICollectionView diffing. AFAICT, the test issue I fixed in #131 was a test-only problem.

@benasher44 benasher44 force-pushed the basher/add-collection-conformance branch from e69beed to 404dbc3 Compare August 28, 2018 16:39
@benasher44 benasher44 force-pushed the basher/differencekit branch from 6d24e30 to 48423ca Compare August 28, 2018 16:51
@benasher44 benasher44 force-pushed the basher/differencekit branch from 48423ca to f155143 Compare August 28, 2018 21:17
@benasher44 benasher44 changed the base branch from basher/add-collection-conformance to master August 28, 2018 21:17
@benasher44
Copy link
Contributor Author

benasher44 commented Aug 28, 2018

@jessesquires this is ready for final review! I think we're happy with internal testing

cc @sasilukr

@benasher44
Copy link
Contributor Author

@jessesquires oh wait no this still needs tests and changelog entry. will update again once that's done.

@benasher44
Copy link
Contributor Author

@jessesquires DifferenceKit properly checks for the presence of the view's window before attempting to perform animated updates, which breaks tests (e.g. means reload data gets called instead of calls to delete sections). Some options:

  1. Delete tests that test the "what is the difference," since we have relegated the responsibility of diffing to a library and therefore falls out of scope of our testing. Instead, we could test "did we attempt to diff as opposed to not diffing".
  2. Figure out how to get a window involved in our tests

Thoughts?

@jessesquires
Copy link
Contributor

@benasher44 Either approach sounds reasonable. You can add the table/collection views to a UIWindow in the tests (I'm pretty sure).

But, I'm leaning toward (1) — seems like we shouldn't be writing tests for the actual diffing lib.

@benasher44
Copy link
Contributor Author

I think best way forward to fixing tests is leveraging protocol-based mocking. I've started with a PR for DifferenceKit: ra1028/DifferenceKit#27

@benasher44
Copy link
Contributor Author

@jessesquires adding the window, properly overriding performBatchUpdates, and remove some super calls gets tests to pass. This is ready for final approval!

Also, confirmed #126 is fixed.

@benasher44
Copy link
Contributor Author

Travis appears to be failing because their specs are out of date.

@PlanBot-iOS
Copy link

1 Warning
⚠️ Big PR

Generated by 🚫 Danger

@benasher44
Copy link
Contributor Author

benasher44 commented Sep 10, 2018

Added pod repo update as a before_install step.

self.model = model

let differenceIdentifier = model.diffingKey
/// Only compares diff identifiers. This means we'll never get "reload"-type `Changeset`s
Copy link
Contributor

Choose a reason for hiding this comment

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

hm... isn't this a problem? what if a cell updates it's content and needs to be refreshed? (but it's diff identifier wouldn't change...)

Copy link
Contributor Author

@benasher44 benasher44 Sep 10, 2018

Choose a reason for hiding this comment

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

We do it manually for the cells on screen in ReactiveLists, which is how it works today (Dwifft doesn't do reloads at all).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could revisit this in the future to see if this is something we want to support (using diffing to animate reloading of cells), but right now it would break forms (e.g. jumping fields because of keyboard dismissal)

Copy link
Contributor

Choose a reason for hiding this comment

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

ah, right 👍 sounds good to me

Copy link
Contributor

@jessesquires jessesquires left a comment

Choose a reason for hiding this comment

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

LGTM! 💯 🥇

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.

[Crash] Auto-diffing bugs and crashes
3 participants