【问题标题】:Dealloc called while method is still running方法仍在运行时调用了 Dealloc
【发布时间】:2012-06-20 20:29:52
【问题描述】:

在我正在处理的一个项目中(我选择了这段代码并一直在尝试调试它),我有一个被观察者调用的函数。观察者调用一个方法来更新要放在屏幕上的数据。在进行此更新时(更新需要几秒钟),用户可以按导航栏上的“返回”按钮,这会导致发生 dealloc 调用。当方法运行时,dealloc 调用释放所有的 ivars,当方法尝试访问 ivars 时最终会导致 EXC_BAD_ACCESS。更新方法的结构也包含在@synchronized 块中。

- (void)update {

@synchronized(self){
  // some code here...
  // Also access ivars here.
  }

}

如何告诉控制器在释放之前先完成方法?我尝试在 dealloc 中运行带有条件的 while 循环,但这似乎效率不高。如果控制器被释放,它也永远不会完全执行,并处于死锁状态。我觉得解决方案很简单,但我的大脑因工作一整天而焦头烂额,无法思考。

【问题讨论】:

    标签: objective-c ios synchronized


    【解决方案1】:

    您可以在self 上调用retain 以确保在运行较长时间的方法时引用计数不会达到零;并以这种方式避免 dealloc:

    - (void) update {
        [self retain]
    
        // do work ...
    
        [self release]
     }
    

    【讨论】:

    • 请注意,您不能在自动引用计数下执行此操作。
    • 这解决了我的问题!我没有意识到这是多么愚蠢的简单。谢谢!
    【解决方案2】:

    如果你把你需要做的工作放在一个块中,编译器会自动保留块内引用的所有对象(包括self)。例如:

    - (void)update {
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            // some code here, access ivars, do whatever you want
        }];
    }
    

    update 方法会立即返回,block 会被安排在主运行循环上运行(这里不涉及辅助线程)。

    如果更新工作是一个长时间运行的任务,您可以使用后台队列而不是主队列,然后(在该块内)安排另一个块在主队列上运行并在工作时与 UI 交互完成了。

    【讨论】:

      【解决方案3】:

      既然您在谈论 NavigationBar,我的猜测是您的 NavigationController 正在释放其对您的 UIViewController 类的引用,而该类又持有 ivars。一种解决方法是将对象保留在视图控制器中,直到进行计算,正如其他答案所暗示的那样。但是,如果您所做的计算是为了计算应在该视图中显示哪些数据,则下次打开同一个视图时,您将重新从头开始重新加载该视图。

      我要做的是在导航控制器之外保留对您正在使用的 ViewController 的引用,这样当用户按下后退按钮时它不会被释放。

      然后,如果用户返回到相同的视图,您将已经加载了数据。只需使用相同的参考再次推动它。

      例子:

      @interface YourRootViewController : UIViewController {
          YourNextControllerClass *nextController;
      }
      
      @property (nonatomic, retain) YourNextControllerClass *nextController;
      
      @end
      

      在您的顶级 ViewController 的 ViewDidLoad 中:

      self.nextController = [[[YourNextControllerClass alloc] initWithNibName:@"YourNextControllerNib" bundle:nil] autorelease];
      

      当你想显示视图时:

      [myNavigationController pushViewController:nextController animated:YES];
      

      如果用户按下后退按钮,viewcontroller 将不会被释放,所以当你再次按下它时,一切都会在你离开时出现。

      【讨论】:

        【解决方案4】:

        解决方案取决于您是否希望在方法结束时保持该对象处于活动状态。但是,您也使用@synchronized (self):如果 self 被释放并且 @synchronized 试图移除对 self 的锁定,我会非常害怕会发生什么,所以在这种情况下,我会尝试让它保持活动状态。 (但是,在我看来,@synchronised 然后运行大量代码并不是一个好主意;@synchronised 应该用于尽可能少的代码以避免死锁)。

        使用 ARC,让对象在方法中保持活动状态很简单。

        typeof (self) myself = self; 
        

        将创建一个对 self 的强引用。最好在方法体中使用我自己而不是自我。

        如果您不想让对象“self”保持活动状态,这将是通常的情况:

        __weak typeof (self) weakSelf = self; 
        

        然后,无论你想确保 self 还在哪里,你都可以写

        typeof (self) strongSelf = weakSelf;
        if (strongSelf != nil) {
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-11-30
          • 1970-01-01
          • 1970-01-01
          • 2013-04-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多