【问题标题】:UINavigationController hidesBarOnSwipe memory leak issueUINavigationController hidesBarOnSwipe 内存泄漏问题
【发布时间】:2018-05-21 12:48:34
【问题描述】:

UINavigationControllerhidesBarOnSwipe 属性有问题。

概述:

Link to project file

我有一个名为 FirstViewController 的控制器,它是 UINavigationController 的根视图。 一切都在Main.storyboard。 FirstViewController 包含UIButton 动作。在该操作中,我实例化了一个 SecondViewController 并将其推送到导航堆栈上。

- (IBAction)button:(id)sender {
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];

    [self.navigationController pushViewController:vc animated:YES];
}

在 SecondViewController 内部,viewDidLoad 上只有一个 hidesBarsOnSwipe 属性设置为 YES

- (void)viewDidLoad {
    [super viewDidLoad];
    self.navigationController.hidesBarsOnSwipe = YES;
}

并且 dealloc 得到 NSLogged :

- (void)dealloc {
    NSLog(@"Dealloc");
}

问题:

当我们向上滑动隐藏 navigationBar 时,不会调用 dealloc。 Instruments 在这里显示了 SecondViewController 内存泄漏。

当我们在 SecondViewController 上时,我们只需按下后退按钮 - 一切都很好。 Dealloc 被调用。

肯定有某种保留周期,但我不知道为什么以及如何避免这种情况。

【问题讨论】:

  • 刚刚遇到同样的问题。 Xcode 9.2(测试版)
  • 这似乎是 iOS 11+ 的问题。在 iOS 10.3 上一切正常-

标签: ios objective-c memory-leaks uinavigationcontroller uinavigationbar


【解决方案1】:

一些更新和临时解决方案:

还有另一种方法可以执行navigationBar 隐藏。 对我有用的是使用:

[self.navigationController setNavigationBarHidden:hidden animated:YES];

为了获得好的效果,在你的类中添加一个属性来跟踪导航栏动画的状态:

@property (assign, nonatomic) BOOL statusBarAnimationInProgress;

像这样实现UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    CGFloat yVelocity = [scrollView.panGestureRecognizer velocityInView:scrollView].y;
    if (yVelocity > 0 && !self.statusBarAnimationInProgress) {
        [self setNavigationBarHidden:NO];
    } else if (yVelocity < 0 && !self.statusBarAnimationInProgress) {
        [self setNavigationBarHidden:YES];
    }
}

设置导航栏隐藏应该是这样的:

- (void)setNavigationBarHidden:(BOOL)hidden {
    [CATransaction begin];
    self.statusBarAnimationInProgress = YES;
    [CATransaction setCompletionBlock:^{
        self.statusBarAnimationInProgress = NO;
    }];
    [self.navigationController setNavigationBarHidden:hidden animated:YES];
    [CATransaction commit];
}

我使用 CATransaction 来检查导航栏的动画是否完成。任何可行的方式。不是那么简单的解决方案,但至少没有泄漏:)

【讨论】: