react-native/Libraries/NativeAnimation/Nodes/RCTStyleAnimatedNode.m
Janic Duplessis c47759a9ae Fix potential retain cycles in Animated iOS
Summary:
Fixes potential retain cycles detected by an internal fb tool.

```
First:

__NSDictionaryM
-> RCTPropsAnimatedNode
-> _parentNodes -> __NSDictionaryM
-> RCTStyleAnimatedNode
-> _childNodes -> __NSDictionaryM

Second:

RCTScrollView
-> _eventDispatcher -> RCTEventDispatcher
-> _observers -> __NSArrayM
-> RCTNativeAnimatedModule
-> _nodesManager -> RCTNativeAnimatedNodesManager
-> _uiManager -> RCTUIManager
-> _viewRegistry -> __NSDictionaryM
-> RCTScrollView
```

First fix:
Use weak map for parent and child nodes, strong refs are managed by RCTNativeAnimatedNodesManager

Second fix:
Make RCTEventDispatcher observers a weak array and make sure we don't keep strong refs to UIManager in RCTNativeAnimatedNodesManager and RCTPropsAnimatedNode.

Tested that native animations still work in UIExplorer

[IOS] [BUGFIX] [NativeAnimated] - Fix potential retain cycles in Animated iOS
Closes https://github.com/facebook/react-native/pull/16506

Differential Revision: D6126400

Pulled By: shergin

fbshipit-source-id: 1ac5083f8ab79a806305edc23ae4796ed428f78b
2017-10-23 13:20:59 -07:00

54 lines
1.6 KiB
Objective-C

/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "RCTStyleAnimatedNode.h"
#import "RCTAnimationUtils.h"
#import "RCTValueAnimatedNode.h"
#import "RCTTransformAnimatedNode.h"
@implementation RCTStyleAnimatedNode
{
NSMutableDictionary<NSString *, NSObject *> *_propsDictionary;
}
- (instancetype)initWithTag:(NSNumber *)tag
config:(NSDictionary<NSString *, id> *)config;
{
if ((self = [super initWithTag:tag config:config])) {
_propsDictionary = [NSMutableDictionary new];
}
return self;
}
- (NSDictionary *)propsDictionary
{
return _propsDictionary;
}
- (void)performUpdate
{
[super performUpdate];
NSDictionary<NSString *, NSNumber *> *style = self.config[@"style"];
[style enumerateKeysAndObjectsUsingBlock:^(NSString *property, NSNumber *nodeTag, __unused BOOL *stop) {
RCTAnimatedNode *node = [self.parentNodes objectForKey:nodeTag];
if (node) {
if ([node isKindOfClass:[RCTValueAnimatedNode class]]) {
RCTValueAnimatedNode *parentNode = (RCTValueAnimatedNode *)node;
[self->_propsDictionary setObject:@(parentNode.value) forKey:property];
} else if ([node isKindOfClass:[RCTTransformAnimatedNode class]]) {
RCTTransformAnimatedNode *parentNode = (RCTTransformAnimatedNode *)node;
[self->_propsDictionary addEntriesFromDictionary:parentNode.propsDictionary];
}
}
}];
}
@end