-
Notifications
You must be signed in to change notification settings - Fork 25k
Fix NativeAnimation invalidation & races on iOS #10663
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
Conversation
|
By analyzing the blame information on this pull request, we identified @buba447 and @janicduplessis to be potential reviewers. |
|
@janicduplessis here it is! |
|
fwiw, I'm working on a large application that makes extensive use of the NativeAnimated API. This diff fixed a boatload of hard to track down bugs. |
216ec54 to
a40dca3
Compare
1dc9155 to
b634c97
Compare
|
Awesome! Tested it and it does fix the node update issues that I had + the weird race conditions that caused some transitions to sometimes not happen at all. Going to review this tomorrow. |
b89a9c5 to
806bbf0
Compare
janicduplessis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! Tested this quite a bit and it did fix the issues you mentioned.
| @@ -0,0 +1,78 @@ | |||
| // | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FB copyright header
| @@ -0,0 +1,350 @@ | |||
| // | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FB copyright header
806bbf0 to
78afc74
Compare
|
@facebook-github-bot shipit |
|
I tried to merge this pull request into the Facebook internal repo but some checks failed. To unblock yourself please check the following: Does this pull request pass all open source tests on GitHub? If not please fix those. Does the code still apply cleanly on top of GitHub master? If not can please rebase. In all other cases this means some internal test failed, for example a part of a fb app won't work with this pull request. I've added the Import Failed label to this pull request so it is easy for someone at fb to find the pull request and check what failed. If you don't see anyone comment in a few days feel free to comment mentioning one of the core contributors to the project so they get a notification. |
|
Should we try this again? Any context on the failed import @javache ? |
|
Looking. |
|
what's going on this? |
|
Ping @hramos |
|
@facebook-github-bot shipit |
|
I tried to merge this pull request into the Facebook internal repo but some checks failed. To unblock yourself please check the following: Does this pull request pass all open source tests on GitHub? If not please fix those. Does the code still apply cleanly on top of GitHub master? If not can please rebase. In all other cases this means some internal test failed, for example a part of a fb app won't work with this pull request. I've added the Import Failed label to this pull request so it is easy for someone at fb to find the pull request and check what failed. If you don't see anyone comment in a few days feel free to comment mentioning one of the core contributors to the project so they get a notification. |
|
why the import failed? is anyone looking into it? I've test this PR with my app, it works so great |
|
Looks like the import failed with an unrelated error. Let's try again. @facebook-github-bot shipit |
|
I tried to merge this pull request into the Facebook internal repo but some checks failed. To unblock yourself please check the following: Does this pull request pass all open source tests on GitHub? If not please fix those. Does the code still apply cleanly on top of GitHub master? If not can please rebase. In all other cases this means some internal test failed, for example a part of a fb app won't work with this pull request. I've added the Import Failed label to this pull request so it is easy for someone at fb to find the pull request and check what failed. If you don't see anyone comment in a few days feel free to comment mentioning one of the core contributors to the project so they get a notification. |
|
@janicduplessis @ryangomba I'm not sure it's Buck-related. Here are the errors that blocked this from landing internally. I know little about Obj-C, do they make sense to you? Looks like this PR needs to be rebased too, sorry about that! |
|
@mkonicek Looks like we're compiling with different warning flags internally and in OSS. Are you using buck to build objc internally? If so I guess it has its own config that probably add different compiler warning flags as the xcbuild one. You might want to ping some ios person about it as it is easy to fix and would prevent import failures like this. |
|
Thanks @janicduplessis! Yes we use Buck. Pinged @mmmulani. |
|
Is there any way you can make the code compile independently of compiler flags to unblock yourself before @mmmulani has time to look into this? |
|
I can follow up on this now that I understand the import error |
6954ca4 to
0e5ab15
Compare
0e5ab15 to
ad5d967
Compare
Summary: This diff attempts to fix a number of iOS native animation bugs related to improper node invalidation and a race with view creation. The major issues were presented in facebook#9120 as problems 3 and 3b, but I'll recap here: The invalidation model we use is overly complicated and incomplete. The proper combination of `_needsUpdate` and `_hasUpdated` will result in nodes values being recomputed. However, we do not invalidate nodes in all the places we should, e.g. if we create a new view and attach it to an existing value node (see example in facebook#9120). This diff chooses to remove the `_hasUpdated` flag, and simply relies on the `_needsUpdate` flag to mark a node as dirty. We mark nodes as dirty when they are: - created - updated - attached to new parents - detached from old parents - attached to a view Calling `updateNodeIfNecessary` will, if necessary, compute all invalidated parent values before recomputing the node value. It will then apply the update, and mark the no Closes facebook#10663 Differential Revision: D4120301 Pulled By: mkonicek fbshipit-source-id: e247afcb5d8c15999b8328c664b9f7e764d76a75
Summary: This diff attempts to fix a number of iOS native animation bugs related to improper node invalidation and a race with view creation. The major issues were presented in facebook#9120 as problems 3 and 3b, but I'll recap here: The invalidation model we use is overly complicated and incomplete. The proper combination of `_needsUpdate` and `_hasUpdated` will result in nodes values being recomputed. However, we do not invalidate nodes in all the places we should, e.g. if we create a new view and attach it to an existing value node (see example in facebook#9120). This diff chooses to remove the `_hasUpdated` flag, and simply relies on the `_needsUpdate` flag to mark a node as dirty. We mark nodes as dirty when they are: - created - updated - attached to new parents - detached from old parents - attached to a view Calling `updateNodeIfNecessary` will, if necessary, compute all invalidated parent values before recomputing the node value. It will then apply the update, and mark the no Closes facebook#10663 Differential Revision: D4120301 Pulled By: mkonicek fbshipit-source-id: e247afcb5d8c15999b8328c664b9f7e764d76a75
Fix iOS native animation (non-nil/non-zero) assertion failure (on initial parentNode then childNode), after nav to bot 4th webview tab (unable to load pages, likely caused by current excluded RN polyfillGlobal) - Df (Foundation) *** Assertion failure in - disconnectAnimatedNodes:childTag - E [com.facebook.react.log:native] Exception thrown while executing UI block: 'parentNode' is a required parameter - Df (Foundation) *** Assertion failure in - connectAnimatedNodes:childTag - E [com.facebook.react.log:native] Exception thrown while executing UI block: 'childNode' is a required parameter Exclude iOS native animation (non-nil/non-zero) assertion macros - for now, when nodes (pointers to tags) attach/detach (to old/new parents and new views) QA: no empty animation frames observed ✅ Low probability possible risks introduced - incomplete node invalidation (outdated nodes) - race condition: prop updated before UIManager created view (outdated props) QA: no outdated animation frames observed ✅ iOS native animation assertion refs - Summary: facebook/react-native@c858420 - PR: facebook/react-native#10663 - Examples: facebook/react-native#9120 - nb: mimics ReactAndroid (i.e. NativeAnimatedNodesManager.java) nb: metro-react-native-babel-preset (0.72.3) - @babel/plugin-transform-regenerator has been removed since initial investigation - @babel/plugin-transform-runtime (removed) - 4 fewer SES warnings - @babel/plugin-transform-runtime > regenerator: false - immediate error thrown (recurring) Todo: Fix webview page loading (likely caused by current excluded RN promisePolyfill), thus fixing these assertion failures on nav, then revert this patch - Problem: Including promisePolyfill (default RN) causes app to boot empty root view Todo: Root cause of above 'regenerator: false' causing nil/zero parent/child nodes
Fix iOS native animation (non-nil/non-zero) assertion failure (on initial parentNode then childNode), after nav to bot 4th webview tab (unable to load pages, likely caused by current excluded RN polyfillGlobal) - Df (Foundation) *** Assertion failure in - disconnectAnimatedNodes:childTag - E [com.facebook.react.log:native] Exception thrown while executing UI block: 'parentNode' is a required parameter - Df (Foundation) *** Assertion failure in - connectAnimatedNodes:childTag - E [com.facebook.react.log:native] Exception thrown while executing UI block: 'childNode' is a required parameter Exclude iOS native animation (non-nil/non-zero) assertion macros - for now, when nodes (pointers to tags) attach/detach (to old/new parents and new views) QA: no empty animation frames observed ✅ Low probability possible risks introduced - incomplete node invalidation (outdated nodes) - race condition: prop updated before UIManager created view (outdated props) QA: no outdated animation frames observed ✅ iOS native animation assertion refs - Summary: facebook/react-native@c858420 - PR: facebook/react-native#10663 - Examples: facebook/react-native#9120 - nb: mimics ReactAndroid (i.e. NativeAnimatedNodesManager.java) nb: metro-react-native-babel-preset (0.72.3) - @babel/plugin-transform-regenerator has been removed since initial investigation - @babel/plugin-transform-runtime (removed) - 4 fewer SES warnings - @babel/plugin-transform-runtime > regenerator: false - immediate error thrown (recurring) Todo: Fix webview page loading (likely caused by current excluded RN promisePolyfill), thus fixing these assertion failures on nav, then revert this patch - Problem: Including promisePolyfill (default RN) causes app to boot empty root view Todo: Root cause of above 'regenerator: false' causing nil/zero parent/child nodes
Fix iOS native animation (non-nil/non-zero) assertion failure (on initial parentNode then childNode), after nav to bot 4th WebView tab (unable to load pages, likely caused by current excluded RN Promise polyfillGlobal) - Df (Foundation) *** Assertion failure in - disconnectAnimatedNodes:childTag - E [com.facebook.react.log:native] Exception thrown while executing UI block: 'parentNode' is a required parameter - Df (Foundation) *** Assertion failure in - connectAnimatedNodes:childTag - E [com.facebook.react.log:native] Exception thrown while executing UI block: 'childNode' is a required parameter Exclude iOS native animation (non-nil/non-zero) assertion macros - for now, when nodes (pointers to tags) attach/detach (to old/new parents and new views) QA: no empty animation frames observed ✅ Low probability possible risks introduced - incomplete node invalidation (outdated nodes) - race condition: prop updated before UIManager created view (outdated props) QA: no outdated animation frames observed ✅ iOS native animation assertion refs - Summary: facebook/react-native@c858420 - PR: facebook/react-native#10663 - Examples: facebook/react-native#9120 - nb: mimics ReactAndroid (i.e. NativeAnimatedNodesManager.java) nb: metro-react-native-babel-preset (0.72.3) - @babel/plugin-transform-regenerator has been removed since initial investigation - @babel/plugin-transform-runtime (removed) - 4 fewer SES warnings - intrinsics: Object.setPrototypeOf.default, Object.setPrototypeOf.__esModule, Reflect.construct.default, Reflect.construct.__esModule - @babel/plugin-transform-runtime > regenerator: false - immediate error thrown (recurring) Todo: Fix WebView page load (likely caused by current excluded RN Promise polyfillGlobal), thus fixing these assertion failures on nav, then revert this patch - Problem: Including (default) RN Promise polyfillGlobal causing app to boot empty root view Todo: Root cause of above 'regenerator: false' causing nil/zero parent/child nodes immediately to reoccur
This diff attempts to fix a number of iOS native animation bugs related to improper node invalidation and a race with view creation. The major issues were presented in #9120 as problems 3 and 3b, but I'll recap here:
Incomplete node invalidation
The invalidation model we use is overly complicated and incomplete. The proper combination of
_needsUpdateand_hasUpdatedwill result in nodes values being recomputed. However, we do not invalidate nodes in all the places we should, e.g. if we create a new view and attach it to an existing value node (see example in #9120). This diff chooses to remove the_hasUpdatedflag, and simply relies on the_needsUpdateflag to mark a node as dirty.We mark nodes as dirty when they are:
Calling
updateNodeIfNecessarywill, if necessary, compute all invalidated parent values before recomputing the node value. It will then apply the update, and mark the node as clean.Note: the simplification also allows us to remove the
cleanupAnimationUpdateroutine.Race condition on view creation
Sometimes, we would attempt to set native animated props on a non-existent view (see example in #9120). This is because we have a race condition with UIManager: sometimes, we run animated updates before UIManager can create the view. To synchronize RCTUIManager and RCTNativeAnimatedModule, we do the following:
RCTNativeAnimatedModulecalls on the UIManager queuebatchDidCompletecall to flush the operation queueRCTNativeAnimatedNodesManagerapply the updates on the main queueThis module + nodeManager structure mimics the one on Android, and I think it works quite well.