2

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

- (void)update {

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

}

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

4

4 回答 4

2

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

- (void) update {
    [self retain]

    // do work ...

    [self release]
 }
于 2012-06-20T20:42:09.070 回答
1

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

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

update 方法将立即返回,并且该块将被安排在主运行循环上运行(此处不涉及辅助线程)。

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

于 2012-06-20T20:51:53.297 回答
0

既然您在谈论 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];

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

于 2012-06-20T21:17:28.610 回答
0

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

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

typeof (self) myself = self; 

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

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

__weak typeof (self) weakSelf = self; 

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

typeof (self) strongSelf = weakSelf;
if (strongSelf != nil) {
}
于 2016-10-21T08:35:46.217 回答