【问题标题】:Removing view from superview iOS从superview iOS中删除视图
【发布时间】:2012-01-06 18:35:06
【问题描述】:

我很难理解为什么下面的第一种方法可以隐藏和删除视图的子视图。在第一种方法中,我通过引用传递指针。在不太通用的第二种方法中,我有一个用于删除特定视图的委托方法。我想使用第一种方法,因为我有几个视图也想应用它。我应该提到,只要在实现类中调用第一种方法,它就不会失败。当我从我希望关闭的视图控制器调用它时,它失败了。当第一种方法失败时,我在 removeFromSuperview 行上得到一个 EXC_BAD_ACCESS。

-(void)closeView:(UIViewController **)viewController
{
 [UIView transitionWithView:self.view 
                   duration:UINavigationControllerHideShowBarDuration
                    options:UIViewAnimationOptionCurveLinear
                 animations:^
  {
   [[*viewController view] setAlpha:0.0];
  }
                 completion:^(BOOL finished)
  {   
   [[*viewController view] removeFromSuperview];
   [*viewController release], *viewController = nil;
  }];
}

-(void)closeButtonClicked
{
 [delegate closeView:&self];
}

//
// This method works without fail:
//

-(void)closeView
{
 [UIView transitionWithView:self.view 
                   duration:UINavigationControllerHideShowBarDuration
                    options:UIViewAnimationOptionCurveLinear
                 animations:^
  {
   // In this context viewController is defined in the class interface
   [[viewController view] setAlpha:0.0];
  }
                 completion:^(BOOL finished)
  {      
   [[viewController view] removeFromSuperview];
   [viewController release], viewController = nil;       
  }];
}

-(void)closeButtonClicked
{
 [delegate closeView];
}

【问题讨论】:

    标签: ios animation delegates viewcontroller


    【解决方案1】:

    首先,在这样的方法中释放 viewController 不符合风格指南,通常也不是一个好主意。它会让你很快陷入困境。如果这个方法的调用者负责 viewController(它已经完成了保留),那么它也应该释放它。这可能是第一种方法在视图控制器本身内不起作用的原因。

    在第二种方法中,你没有将viewController作为参数传入,这意味着它需要在上下文中定义。

    如果你在这个方法中不释放viewController,那么你也不需要将它的变量设置为nil,你可以简单地将它作为普通参数传递:

    -(void)closeView:(UIViewController *)viewController
    {
     [UIView transitionWithView:self.view 
                       duration:UINavigationControllerHideShowBarDuration
                        options:UIViewAnimationOptionTransitionCrossDissolve
                     animations:^
      {
        [[viewController view] removeFromSuperview];
      }
                     completion:nil];
    }
    

    然后您将在呼叫站点执行此操作:

    [self closeView:childViewController];
    [childViewController release]; childViewController = nil;
    

    在动画完成之前以这种方式释放孩子是安全的,因为动画块隐式地保留了从该块引用的所有对象,包括 viewController 参数。因此,在动画块释放它之前,不会调用孩子的 dealloc。 这在您的第一个代码示例中不起作用,因为您将指针传递给变量。也就是说,动画块不知道它需要保留孩子。

    顺便说一句,我不确定您为什么要设置 alpha,在上面的示例中,我展示了您也可以删除动画块中已经存在的视图。在UIView Class Reference 中查看更多信息。

    【讨论】:

    • 感谢您关于不需要 alpha 的建议。这是个好消息。让我再解释一下我的推理,以便您了解我为什么要发布正在删除的视图。我这样做是为了将操作的处理与正在显示的子视图分离。我希望父母视图决定如何处理孩子。我不希望此操作的默认操作是删除和取消子视图。话虽如此,我不明白为什么父母将孩子从视图中删除并取消它是有问题的。你能解释一下吗:)
    • 就像添加的评论一样,removefromsuperview 在块中没有动画。我仍然必须将它与动画中的 alpha 一起放入完成块中才能按需要工作。我做错了吗?
    • @PatrickHogan 抱歉,我应该正确调整您的代码。对于 options: 参数,您需要选择 UIViewAnimationOptionTransition 选项之一,以便将动画应用于已移除的视图。 CrossDissolve 可能是您想要的。我将修改代码以显示这一点。
    • @PatrickHogan 关于发布:父母从视图中删除孩子并没有错,而您可以使用 removeFromSuperView 做到这一点。但是将变量的地址传递给其他人并要求它为您释放和取消它是非常令人困惑的。实际上,这很可能是 EXC_BAD_ACCESS 错误的来源:您忘记了 closeView 现在负责释放,并且还在动画运行时将其释放到另一个地方(可能是父级的 dealloc?)。 “[*viewController view]”然后引用一个已经发布的对象。
    • 感谢有关过渡的更新。另外,我在子视图的 dealloc 中放置了一个断点,并且在执行完成块之前不会调用它。完成块在那里,因此在动画完成之前不会进行清理。我必须传递地址,以便我可以将其设置为零。如果我只传递指针并释放它一切正常。对于为什么这在这种情况下不起作用,我仍然有点困惑,但我想我会把它归结为一个看不见的错字或逻辑错误,直到我找到更多证据。感谢您的跟进:)
    【解决方案2】:

    **viewcontroller 和 &self 不是要走的路。在 Objective-C 中,您在子视图本身中执行 [self.view removeFromSuperview],在父视图控制器中您执行 release 或使用 ARC 只需将子视图替换为另一个视图。

    【讨论】:

    • 感谢您的建议,我在上面留下了详细的评论来解释我的立场。您能否在所写内容的背景下澄清您的:)?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多