5

该问题已在此处此处进行了讨论,但我想知道是否有更可靠的方法来解决此问题,无论您是否有委托 - 在延迟后调用函数时。在程序中的某个点,按一下按钮,就会创建一个对象 - CCLayer。该层创建了几个对象,其中一些在回调中。创建的对象层有一个“后退”按钮,可以破坏它。当对象被破坏并尝试访问不再存在的对象后触发回调等时,我遇到了一个问题——“发送到已释放实例 0x258ba480 的消息”给了我这个好消息。我该如何避免呢?

1)有没有办法杀死回调(因为我显然不再需要它们了) 2)我应该/我可以在回调本身测试这些可能不存在的对象的存在 3)别的什么?

(我的回调是用于检查我从这个杰出网站复制的互联网连接的代码 - 愿它长寿和繁荣 - 使用可达性,我可以通过简单地将其移动到主视图并在子视图,但我不想。)

- (void)testInternetConnection
{
    internetReachableFoo = [Reachability reachabilityWithHostname:@"www.google.com"];

    // Internet is reachable
    internetReachableFoo.reachableBlock = ^(Reachability*reach)
    {
         // Update the UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Yayyy, we have the interwebs!");
            //I do the net stuff here
    });
};

// Internet is not reachable
internetReachableFoo.unreachableBlock = ^(Reachability*reach)
{
    // Update the UI on the main thread
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"Someone broke the internet :(");
        noNetMessageLabel.visible=true; //<-------this goes kaboom
        noNetFlag=true;

    });
};

[internetReachableFoo startNotifier];

}

4

2 回答 2

5

基本上有两种方法可以避免向解除分配的委托发送消息:

  1. 抓住稍后要发送消息的对象。这样他们就不会被释放。块回调就是这种情况——如果一个块引用了某个对象,则该对象将被保留,直到该块不再存在。如果您从一个块中向某些对象发送消息并命中一个已释放的对象,那么您一定是在某处搞砸了内存管理。

  2. 在释放委托之前清除委托链接。如今,这通常使用弱的归零属性来完成,这些属性会nil在引用对象被释放时自动设置为。很方便。不是你的情况。

于 2013-10-01T13:41:46.020 回答
3

您可以考虑几个选项:

首先,您可以在将消息传递给它之前检查对象是否存在:

if (noNetMessageLabel)
  noNetMessageLabel.visible = true;

但我个人认为这是一个糟糕的架构。

从我的角度来看,更明智的决定是将显示有关互联网连接的任何警报的代码移动到模型。在 AppDelegate 或模型中创建这样的方法:

- (NSError*)presentConnectivityAlert
{
   if () //any error condition checking appropriate
       [[NSNotificationCenter defaultCenter]
          postNotificationName:@"connectivityAlert"
          object:self
          userInfo:userInfo];
}

您也可以考虑将互联网检查代码也移动到模型中。

在你的应用的 ViewControllers 中实现监听这个通知。

- (void)viewDidLoad {
    [[NSNotificationCenter defaultCenter] 
      addObserver:self
      selector:@selector(didReceiveRemoteNotification:)                                                  
      name:@"connectivityAlert"
      object:nil];
}

- (void)viewDidUnload {
[[NSNotificationCenter defaultCenter] 
  removeObserver:self
  name:@"connectivityAlert"
  object:nil];
}

-(void)didReceiveRemoteNotification:(NSDictionary *)userInfo {
   if (self.isViewLoaded && self.view.window) {
      //Present the user with alert
   }
}

因此,您可以使用更通用、更通用的方法来处理所有应用程序中的连接问题。

有没有办法杀死回调

无法取消块(在您的情况下),但可以取消 NSOperationQueue 中的 NSOperation。但这需要重写您的可达性实现。

于 2013-10-01T14:02:28.907 回答