【问题标题】:How to transition between two UIView's using a custom UIViewController without memory leaks?如何在没有内存泄漏的情况下使用自定义 UIViewController 在两个 UIView 之间进行转换?
【发布时间】:2011-03-15 20:12:17
【问题描述】:

我正在尝试使用视图模拟翻书页。当查看打开的书时,每个 UIView 显示两个页面(左和右)。翻页时,应该显示一个新的 UIView。我目前的方法是使用带有空白根 UIView 的自定义 UIViewController 并将页面设置为子视图。当我添加一个新的子视图时,我会从添加的最后一个子视图过渡到新的子视图。转换完成后,我想删除之前的最后一个子视图,因为它不再需要 - 它不再可见并占用内存。

本质上是这样的:

UIView * myOldPageView = [[self.view subviews] lastObject];
[self.view addSubview:myNewPageView];
// ... transition between the two views
[myOldPageView removeFromSuperview];

这是我最初的尝试,但由于没有堆栈跟踪的神秘崩溃而失败。这个方法在我自定义的 UIViewController 中:

-(void) switchToController:(UIViewController *) controller {
    [controller viewWillAppear:YES];        

    if (self.currentScreenController != nil) {
        [self.currentScreenController viewWillDisappear:YES];
    }

    [self.view addSubview:[controller view]];

    if (self.currentScreenController != nil) {
        [[self.currentScreenController view] removeFromSuperview];
        [self.currentScreenController viewDidDisappear:YES];
    }

    self.currentScreenController = controller;

    [controller viewDidAppear:YES];
}

在此方法调用后执行[controller release] 会导致崩溃,这很奇怪,因为保留计数大于 0。如果我不执行释放,我会出现内存泄漏。

[编辑] 这是另一种不使用控制器的方法,当旧页面视图从其父视图中删除时会崩溃:

-(void) switchToView:(UIView *) screen {
  [self.view addSubview:screen];
  [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:screen cache:NO];
  [UIView commitAnimations];
  if (3 < [[self.view subviews] count]) {
    [[[self.view subviews] objectAtIndex:0] removeFromSuperview]; // <- crash
  }
}

[编辑]即使我尝试在添加新子视图后立即删除它,我也会崩溃,没有过渡动画:

 -(void) switchToView:(UIView *) screen {
   [self.view addSubview:screen];
   if (3 < [[self.view subviews] count]) {
     [screen removeFromSuperview]; // <- crash
    }
  }

[Edit] 我现在坚信问题在于释放添加的视图,这意味着它与动画或视图控制器无关。

【问题讨论】:

  • [myOldPageView removeFromSuperview];也可以
  • 您是否开启了 NSZombieEnabled 以防万一?
  • @Nick 我没有结果。我开始认为两个控制器之间存在公共视图所有权的内部冲突——只有一个控制器可以拥有一个视图,而这里的根控制器和参数控制器都将拥有同一个视图。尽管如此,我仍然需要一个解决方案。
  • 你能再指出一些为什么你必须切换到不同的 UIViewController 吗?你先说每个页面都是一个UIView,我现在有点糊涂了。
  • 尝试添加一个 beginAnimations:context 来完成动画。控制台现在是否产生更具描述性的错误消息?

标签: iphone uiview uiviewcontroller


【解决方案1】:

你可能想看看 UIView 方法transitionFromView:toView:duration:options:completion:

使用options:可以指定页面卷曲效果。

来自文档:讨论 该方法是一种从fromView参数中的视图过渡到toView参数中的视图的简单方法。默认情况下,fromView 中的视图在视图层次结构中被 toView 中的视图替换。如果两个视图都已经是视图层次结构的一部分,则可以在 options 参数中包含 UIViewAnimationOptionShowHideTransitionViews 选项来隐藏或显示它们。

【讨论】:

  • 我的目标是4.0之前的iOS
【解决方案2】:

尝试 removeFromSuperview 您要处置的视图。

【讨论】:

  • 你是对的,但我写错了问题,现在更正了。原来的问题如下。我试图弄清楚是否有另一种方法可以尝试从我的工作中实现这一目标。
【解决方案3】:

这只是来自文档,但我们开始了:使用 NavigationController 并在其中操作数组

- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated

添加到数组的最后一项成为导航堆栈的顶部项。来自文档:

如果启用了动画,这个方法 决定过渡到哪种类型 根据是否最后一项执行 在 items 数组中已经在 导航堆栈。如果视图 控制器当前在堆栈中, 但不是最上面的项目,这个 方法使用弹出过渡;如果是 最上面的项目,没有过渡是 执行。如果视图控制器是 不在堆栈上,此方法使用 推动过渡。只有一个过渡 被执行,但是当那个过渡 完成后,整个内容 堆栈被新视图替换 控制器。例如,如果 控制器 A、B 和 C 位于 堆栈并设置控制器 D、A、 和 B,此方法使用 pop 转换和结果堆栈 包含控制器 D、A 和 B。

即如果您有视图控制器 A 和 B,则创建数组

{A, B} {B,A} {一种} {B}。

假设您从第一页开始是 A。然后您想要推送到 B,将数组设置为 {B},请注意:

如果视图控制器不在 堆栈,此方法使用推送 过渡。

下一次,将其设置为 {A} 等以进行正向迭代。 现在,如果您想要从 B 到 A 的 pop 过渡,请注意

如果视图控制器当前在 堆栈,但不是最顶层 项目,此方法使用弹出 过渡;

您将其设置为 {B, A},反之亦然,从 A 到 B。当然,在动画之后(?),只需返回 {A} 和 {B} 数组即可返回起点 - 如果视图控制器已经是最顶层的,不执行任何转换。祝你好运;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-02
    • 1970-01-01
    • 2011-07-27
    • 2021-12-19
    相关资源
    最近更新 更多