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

Develop 0.0.4 swift3 #5

Merged
72 commits merged into from Jun 21, 2018
Merged

Develop 0.0.4 swift3 #5

72 commits merged into from Jun 21, 2018

Conversation

tapi
Copy link
Contributor

@tapi tapi commented Dec 5, 2016

Just creating a PR to highlight the diff

Was a little murky/magic/weird.  Replaced it with 2 (saner) free
functions in AssociatedObjects.swift
Converted the Subscribable protocol into a class.  Rationale: it was
becoming very unsustainable to keep adding type constraints everywhere.
Additionally, realistically, we don't gain too much (anything) from it
being a protocol.
Added the concept of 'BindingHandlers'.  The basic idea is they wrap up
the logic involved in updating the UI with a new value.  This allows
for client code to customize exactly how the UI is updated.

Some potential uses for custom written binding handlers could include:
  - Animating changes
  - Reusable transforms (instead of the current transform block on
    bind())
  - Formatters (ie, could build a BindingHandler that uses a
    NSNumberFormatter to transform an Observable<Int> into a String)
  - "Debouncing"/delaying when changes are applied to the UI
  - Filtering (ie: "only update the UI when value is ...")
  - More complex logic (ie: re-rendering a UIImage when a value
    changes)

A default BindingHandler (DefaultBindingHandler) is provided that
simply updates

Additionally, refactor BindableProperty.bind(subscribable:transform:)
to use a custom BindingHandler for doing the transform.
Added `BindingHelpers` struct to namespace some BindingHandler creation
functions.  These helper functions are used because initializers are
somewhat constrained (ie, can't specify a same type requirement for 2
generic type parameters)
Begin adding support for using BindingHandlers for
BidirectionalBindableProperty's.  Currently just hardcoded to
DefaultBindingHandler.

NOTE: Some of the logic that bubbles changes up through the
BindingHandler to the bound Observable are a little murky, might be
worth looking at reworking that logic.
BidirectionalBindableProperty's now work with TransformBindingHandler.
Added checks (and a test) to prevent a BidirectionalBinding from
infinite looping in the case it uses a BindingHandler that prevents
weird values. (ie a TransformBindingHandler where the `transform` &
`reverseTransform` blocks don't actually produce the inverse of the
other)
Should be using the `.bind(...)` methods
On BindableProperty & BidirectionalBindableProperty, deprecated the
follow overloads of `bind()`:

- `bind(_, transform:)`   (should use a TransformBindingHandler to
  transform the value)
- `bind(block:)`   (should use a Computed)

Goal is to converge on a single (or as few as possible) `bind(...)`
method (as opposed to having these extra overloads & the custom
operators)
Binding a Subscribable<T> to a BindableProperty<T?> is now supported.
Fixes GH issue #1
BidirectionalBindableProperty<T?> now supports binding to
to Observable<T> (or Subscribable<T>)

Related to GH issue #1
Updated the UIKit class extensions so that the BindableProperty's
(and BidirectionalBindableProperty's) ValueType has the same
nullability as the original UIKit property.
Added a BindableProperty for UIImageView.image

Additionally, added support for loading images from URL's via
LoadImageBindingHandler.
(to allow it to be subclassed outside of the Fisticuffs modulue)
Essentially a Computed, but allows defining a custom setter
Computed/WritableComputed were (incorrectly) tracking additional
dependencies (any dependencies accessed inside by its subscribers)
Fixed bug where UITableView/UICollectionView bindings wouldn't select
preselected items (because selectRowAtIndexPath was being called
before the view had loaded data, so the selection was being discarded
by UIKit)
Computed now coalesces updates.  So, if 3 of its dependencies change
in a single run loop, it'll only recompute itself once.

NOTE: Because it uses subscriptions for tracking dependencies, if it
depends on a Computed, it'll take 2 runloops to for a change to bubble
up.  Will be fixing it so it only takes the regular one run loop.
Because Computed's updates are coalesced now, it could have taken 2+
runloops for a change to propagate up.  For example, a change to C
would take 2 runloops to propagate up to A:

  A (computed) <- B (computed) <- C (observable)

This commit fixes that.
Previously was calculating twice, when it really didn't need to
calculate it the second time.
Updated WritableComputed to have the same behaviour as Computed for
coalescing updates
Improved performance of Computed / WritableComputed by reducing the
number of times their value is recomputed
WritableComputed wasn't immediately recomputing it's value when .value
was accessed.  Fixed & added tests to verify.
If a Computed's (or WritableComputed's) value was read in a
subscription block, like:

  let a = Observable(5)
  let result = Computed { a.value }
  result.subscribe { [weak result] in
  	result?.value
  }

it would infinitely recurse.  This commit fixes that.
darrenclark and others added 8 commits July 6, 2016 13:46
If `value` was accessed after a update was scheduled, any observers
were being notified twice for the same change; once when accessing
`value`, and once when the update happened next run loop.

This commit fixes that
DependenciesCollectionStack now uses a custom NSObject subclass as it's
key in NSThread.threadDictionary so that it avoids doing string
comparison (improves performance significantly)
Now computes the result immediately, fixes a potential flickering
issue with reused table/collection view cells
- Update project to Swift 3
- Run Swift migrator & add manual fixes
- Update Quick & Nimble to latest versions
var b_title: BindableProperty<UIButton, String?> {
return associatedObjectProperty(self, &b_title_key) { _ in
return BindableProperty(self) { control, value in
control.setTitle(value, for: UIControlState())
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@darrenclark This is what I was talking about with the migrator blowing away the enum.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ohhhh jeez, that's sneaky

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it only seems to happen for the first enum case

Copy link
Contributor

Choose a reason for hiding this comment

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

Ahh right, and since UIControlStateNormal = 0, it should turn out okay

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For sure, its just not at all descriptive. And what is the behaviour if your enum starts in the negatives

Copy link
Contributor

Choose a reason for hiding this comment

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

Yea true.

For what it's worth, for OptionSet's like this, it should always default to 0, regardless of if it starts in the negatives or not: https://developer.apple.com/reference/swift/optionset/1641258-init (unless someone overrides init())

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hadn't realized UIControl was an option set, can think of a single time I've ever used more than one option.

Still don't like empty over .normal but I guess thats just a preference thing

robinsenior and others added 16 commits December 21, 2016 10:54
…compiler crash and warning when using Swift 3.1.
If the UICollectionView hadn't been on screen yet & we attempted to
insert or delete cells, UICollectionView would raise an exception.
This commit fixes the issue by just doing a regular reloadData() if the
collection view hasn't loaded data yet.  (see comment in code diff for
more details)
…before-initial-data-load

Fix potential UICollectionView crash
Wrapping all updates in calls to performUpdate(_:completion:) to work
around crash that occurred when inserting/removing items before the
collection view had done its initial load of section/item counts. See
comments in code for specifics.

Additionally am calculating the changes using DataSource's `items`
array & the new items from the subscribable.  Previously it was using
`subscribeArray`, which did a diff of the subscribable's old value
& new value.  Not sure if it was the source of any bugs, but now by
using `DataSource.items` & the new items, we are definitely diffing
what the UICollectionView will see in terms of updates.
…erting-items-before-initial-data-load

Improve fix for UICollectionView crash
@ghost
Copy link

ghost commented Jun 21, 2018

lol @tapi @darrenclark can we merge this to master?

@tapi
Copy link
Contributor Author

tapi commented Jun 21, 2018

Is it even needed anymore?

@darrenclark
Copy link
Contributor

darrenclark commented Jun 21, 2018

Yea, lets merge it 👍, we've been using it for a while & it hasn't given us any trouble

@ghost ghost merged commit 73b82c6 into master Jun 21, 2018
@ghost ghost deleted the develop-0.0.4-swift3 branch June 21, 2018 18:25
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants