如何使用自定义UIViewController在没有内存泄漏的情况下在两个UIView之间进行转换?

时间:2011-03-15 20:12:17

标签: iphone uiview uiviewcontroller

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

从本质上讲,就是这样:

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
    }
  }

[编辑]我现在强烈认为问题在于解除分配添加的视图,这意味着它与动画或视图控制器无关。

3 个答案:

答案 0 :(得分:3)

您可能需要查看UIView方法transitionFromView:toView:duration:options:completion:

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

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

答案 1 :(得分:0)

尝试删除您要处置的视图的removeFromSuperview。

答案 2 :(得分:0)

这只是来自文档,但我们在这里:使用NavigationController并操纵

中的数组
- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated

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

  

如果启用了动画,则此方法   决定转换的类型   根据是否最后一项执行   在items数组中已经在   导航堆栈。如果是看法   控制器目前在堆栈中,   但这不是最重要的项目   方法使用pop转换;如果是   最顶层的项目,没有过渡   执行。如果视图控制器是   不在堆栈上,此方法使用a   推动转型。只有一个过渡   执行,但转移时   完成,整个内容   堆栈将替换为新视图   控制器。例如,如果   控制器A,B和C在上面   堆栈,你设置控制器D,A,   和B,这个方法使用pop   过渡和结果堆栈   包含控制器D,A和B.

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

{A,B} {B,A} {一个} {B}。

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

  

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

下次将其设置为{A},依此类推,以便向前进行迭代。 现在,如果您想要从B到A的弹出过渡,请注意

  

如果视图控制器当前处于   堆栈,但不是最顶层的   item,此方法使用pop   过渡;

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