【问题标题】:Remove delegate on dealloc from unreferenced object从未引用的对象中删除 dealloc 上的委托
【发布时间】:2010-01-20 23:52:38
【问题描述】:

如果你学会了如果委托的生命周期比对象短,你应该从对象中删除委托。但是,如果您不再引用该对象,该怎么做呢?

在我的 iPhone 应用程序中,我有一个视图控制器 vc,它执行异步活动并显示为模式视图。取消按钮关闭模式视图。如果发生错误,则会显示 UIAlertView alert。如果用户点击 ok,alert 和模态视图都会消失。因此设置了vc 作为alert 的代表并实现alertView:didDismissWithButtonIndex:。像这样的:

// UIViewController vc
    ...
    UIAlertView *alert = [[UIAlertView alloc]
                          initWithTitle:@"Error"
                          message:@"Something went wrong"
                          delegate:self
                          cancelButtonTitle:@"OK" 
                          otherButtonTitles:nil];
    self.alertView = alert; // needed to unset alertView.delegate in dealloc
    [alert show];
    [alert release];
    ...
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
        [self dismissModalViewControllerAnimated:YES];
    } 
}

通常,警报视图会阻止所有输入。不幸的是,它在某些边缘情况下无法做到这一点。 如果用户在警报视图出现之前按下取消按钮,并在警报视图出现后触摸取消按钮,则视图将被关闭,但警报不会。 vc 被释放,如果用户在警报上点击“确定”,应用程序将崩溃,因为一条消息被发送到释放的对象。

我通过将alert 分配给vc 的属性解决了这个问题,因此我可以在dealloc 中将alert.delegate 设置为nil。我发现这个解决方案不是很优雅,因为我真的不需要对 alert 的引用。

有更好的方法吗?

编辑:添加了斜体中的文本作为说明

【问题讨论】:

    标签: iphone objective-c delegates


    【解决方案1】:

    虽然,通常会在不变的内容上显示警报视图。因此,如果代理在视图出现时还活着,那么它在被解除时很可能是活着的。如果不是这种情况,您必须完全按照您所做的那样做,如果您不再关心它的结果,请手动取消设置警报视图的委托。

    所以您确实关心警报视图,因为您关心它的委托方法。问题是,在解除警报时,代表可能不会申请。因此,您需要那里的逻辑,并且对于该逻辑,您需要保存对相关警报视图的引用。

    换句话说,你做对了。虽然,如果 UIAlertView 保留它的委托可能会有所帮助,但如果它在被解除时崩溃,它似乎就没有用了。

    最后,我认为警报视图阻止了所有屏幕输入?如果没有,您可以通过在警报出现时设置vc.view.userInteractionEnabled = NO 来使其真正成为模态,并在警报消失时将其切换回来。这样用户就不能在警报视图启动时关闭控制器。这对我来说听起来更理智一些。

    【讨论】:

    • 我尝试设置 userInteractionEnabled = NO 但取消按钮上的 touchUp 仍在处理中。我可能不得不忍受对警报方式的引用。
    【解决方案2】:

    从 UI 的角度来看,当警报视图出现时,它应该要求用户全神贯注。当存在警报视图时,您可能会考虑禁用取消按钮(以及任何其他可见的非警报视图小部件),并向执行相同任务的UIAlertView 实例添加按钮标题。这将提供更清晰的用户界面,并且还应该巧妙地解决您的内存问题。

    【讨论】:

      【解决方案3】:
      -(void)delayedDismiss {
          [self dismissModalViewControllerAnimated:YES];
      }
      
      - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
          [self performSelector:@selector(delayedDismiss) withObject:nil afterDelay:0.0];
      
      }
      

      【讨论】:

        【解决方案4】:

        如果您不再关心 UIAlertView 的结果,您可能也应该在 - (void) viewWillDisappear:(BOOL)animated 中将其关闭

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-06-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-05-05
          • 1970-01-01
          • 2011-05-01
          相关资源
          最近更新 更多