mirror of
https://github.com/status-im/react-native.git
synced 2025-01-10 17:45:59 +00:00
d8dd330d41
Summary: The memory leaks root from the TabBarController not removing itself when its holder view deallocs. So to fix the issue, it’s just to remove it from its parentViewController when the holding RCTTabBar deallocs. This should be safe, since the RCTTabBar seems the owner of the TabBarController. Closes https://github.com/facebook/react-native/pull/3915 Reviewed By: svcscm Differential Revision: D2620905 Pulled By: nicklockwood fb-gh-sync-id: ce22eb3ebf82562827f6b1bae22aea5ac7d3b51a
158 lines
3.8 KiB
Objective-C
158 lines
3.8 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 "RCTTabBar.h"
|
|
|
|
#import "RCTEventDispatcher.h"
|
|
#import "RCTLog.h"
|
|
#import "RCTTabBarItem.h"
|
|
#import "RCTUtils.h"
|
|
#import "RCTView.h"
|
|
#import "RCTViewControllerProtocol.h"
|
|
#import "RCTWrapperViewController.h"
|
|
#import "UIView+React.h"
|
|
|
|
@interface RCTTabBar() <UITabBarControllerDelegate>
|
|
|
|
@end
|
|
|
|
@implementation RCTTabBar
|
|
{
|
|
BOOL _tabsChanged;
|
|
UITabBarController *_tabController;
|
|
NSMutableArray<RCTTabBarItem *> *_tabViews;
|
|
}
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
{
|
|
if ((self = [super initWithFrame:frame])) {
|
|
_tabViews = [NSMutableArray new];
|
|
_tabController = [UITabBarController new];
|
|
_tabController.delegate = self;
|
|
[self addSubview:_tabController.view];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
|
|
|
- (UIViewController *)reactViewController
|
|
{
|
|
return _tabController;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
_tabController.delegate = nil;
|
|
[_tabController removeFromParentViewController];
|
|
}
|
|
|
|
- (NSArray<RCTTabBarItem *> *)reactSubviews
|
|
{
|
|
return _tabViews;
|
|
}
|
|
|
|
- (void)insertReactSubview:(RCTTabBarItem *)view atIndex:(NSInteger)atIndex
|
|
{
|
|
if (![view isKindOfClass:[RCTTabBarItem class]]) {
|
|
RCTLogError(@"subview should be of type RCTTabBarItem");
|
|
return;
|
|
}
|
|
[_tabViews insertObject:view atIndex:atIndex];
|
|
_tabsChanged = YES;
|
|
}
|
|
|
|
- (void)removeReactSubview:(RCTTabBarItem *)subview
|
|
{
|
|
if (_tabViews.count == 0) {
|
|
RCTLogError(@"should have at least one view to remove a subview");
|
|
return;
|
|
}
|
|
[_tabViews removeObject:subview];
|
|
_tabsChanged = YES;
|
|
}
|
|
|
|
- (void)layoutSubviews
|
|
{
|
|
[super layoutSubviews];
|
|
[self reactAddControllerToClosestParent:_tabController];
|
|
_tabController.view.frame = self.bounds;
|
|
}
|
|
|
|
- (void)reactBridgeDidFinishTransaction
|
|
{
|
|
// we can't hook up the VC hierarchy in 'init' because the subviews aren't
|
|
// hooked up yet, so we do it on demand here whenever a transaction has finished
|
|
[self reactAddControllerToClosestParent:_tabController];
|
|
|
|
if (_tabsChanged) {
|
|
|
|
NSMutableArray<UIViewController *> *viewControllers = [NSMutableArray array];
|
|
for (RCTTabBarItem *tab in [self reactSubviews]) {
|
|
UIViewController *controller = tab.reactViewController;
|
|
if (!controller) {
|
|
controller = [[RCTWrapperViewController alloc] initWithContentView:tab];
|
|
}
|
|
[viewControllers addObject:controller];
|
|
}
|
|
|
|
_tabController.viewControllers = viewControllers;
|
|
_tabsChanged = NO;
|
|
}
|
|
|
|
[_tabViews enumerateObjectsUsingBlock:
|
|
^(RCTTabBarItem *tab, NSUInteger index, __unused BOOL *stop) {
|
|
UIViewController *controller = _tabController.viewControllers[index];
|
|
controller.tabBarItem = tab.barItem;
|
|
if (tab.selected) {
|
|
_tabController.selectedViewController = controller;
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (UIColor *)barTintColor
|
|
{
|
|
return _tabController.tabBar.barTintColor;
|
|
}
|
|
|
|
- (void)setBarTintColor:(UIColor *)barTintColor
|
|
{
|
|
_tabController.tabBar.barTintColor = barTintColor;
|
|
}
|
|
|
|
- (UIColor *)tintColor
|
|
{
|
|
return _tabController.tabBar.tintColor;
|
|
}
|
|
|
|
- (void)setTintColor:(UIColor *)tintColor
|
|
{
|
|
_tabController.tabBar.tintColor = tintColor;
|
|
}
|
|
|
|
- (BOOL)translucent {
|
|
return _tabController.tabBar.isTranslucent;
|
|
}
|
|
|
|
- (void)setTranslucent:(BOOL)translucent {
|
|
_tabController.tabBar.translucent = translucent;
|
|
}
|
|
|
|
#pragma mark - UITabBarControllerDelegate
|
|
|
|
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
|
|
{
|
|
NSUInteger index = [tabBarController.viewControllers indexOfObject:viewController];
|
|
RCTTabBarItem *tab = _tabViews[index];
|
|
if (tab.onPress) tab.onPress(nil);
|
|
return NO;
|
|
}
|
|
|
|
@end
|