如何解决/处理委派EXC_BAD_ACCESS错误? Obj C

我正在编写一个我想要打包和销售的库(Obj-C for iPhone),所以我显然需要在出售之前找出任何devise扭结。 我也利用这个库来帮助我开发另一个应用程序。

我的图书馆是build立在任务授权之上的。 我所拥有的主要function是启动一个(可能)长时间运行的过程,当完成时,我会在类的委托中调用委托协议方法。

另外一个复杂的因素是,我会经常安排这个任务每隔30秒左右发射一次。 通常,我使用[self performSelector:@selector(someMethod 🙂 withObject:nil afterDelay:30]来执行此操作,而不是使用NSTimer。 然后,当委托方法成功返回时,我处理返回的数据并触发另一个30秒的方法。 这给我30秒间BETWEEN方法调用,而不是从一个呼叫开始到下一个30秒。 (这主要是为了防止电话超过30秒,这不应该发生。)

我遇到的错误是,有时,委托callback方法失败,出现EXC_BAD_ACCESS错误。 根据我的调查,自从长期运行的过程开始以来,我的class级代表似乎已经消失了(被释放/处理)。 因此,当它调用[[self Delegate] doSomeDelegateMethod]时,它正在访问一个已发布的对象。

我试着首先检查[[自我委托] respondsToSelector:@selector(doSomeDelegateMethod)],但即使该访问显然也会引发EXC_BAD_ACCESS。

似乎还没有检查[self Delegate] ==零是正确的路要走。

一种方法,我想我已经解决了这个问题,在这个特定的情况下,是实例化我的对象的视图控制器正在消失(因此在垃圾转储的途中),我调用[NSObject cancelPreviousPerformRequestsWithTarget:self]。 这显然解决了这个问题。 (这个“修复”是否也表明我的对象“知道”来电的呼叫,并保持自己的记忆,直到它能够成功,拼命地开除最后的镜头?)

这似乎把一个创可贴的伤口。 是的,这似乎阻止我的应用程序打破这一次,但我的直觉告诉我,这是一个糟糕的解决scheme。

我也考虑过在我的viewWillDisappear:animated:方法中将自定义对象设置为零,这可能是正确的编码模式,但客户在处理我的对象时不得不如此精确。

然而,真正困扰我的是,作为一个图书馆开发者,我还没有find一种方法来“框入”我的代码,以便它不会为用户抛出exception,如果他们不做正确的事情。 基本上,我想要一个方法来得到我的对象:

  1. 获取请求。
  2. 去寻找答案。
  3. find答案。
  4. 尝试返回答案。
  5. 意识到在另一端没有任何东西。
  6. 放弃自己而死。 (好吧,“自己死”可能不会发生,但你明白了。)

一个有趣的一面:

我有防止这种types的错误发生的主要原因是这样的:

我做了以下步骤:

  1. 构build我的库的.h / .m文件。
  2. 生成我的库的.a输出文件。
  3. 将我的图书馆的.a / .h文件导入到另一个项目中。
  4. 有上面描述的错误。
  5. 必须仔细阅读.m文件中应该隐藏在.a文件中的代码。

我在这里错过了什么? 如果它为客户端引发错误,我真的冒着暴露我的整个源代码的风险吗? (这只是一个小问题,但我很关心这里!)

感谢您提供帮助我成为更好的程序员的任何帮助!

– -编辑 – –

我发现了这个重要的另一个原因。 在另一个视图控制器中,我使用这个库,我实现了NSTimer策略。 如果视图从导航堆栈中popup(即在viewWillDisappear:animated:方法中),则使所述定时器无效。 所以,在视图消失后,再也没有电话会去我的图书馆了。

这就是问题:如果视图在长时间呼叫的中间消失,该怎么办? 是的,这是棘手的,不太可能做到,但我只是在模拟器上发生。 特别是, 就是为什么我正在寻找一种解决方法,让我的代码实现“嘿,这个pipe道的另一端没有任何东西”,然后优雅地失败。 任何人?

谢谢!

这个问题有几种方法:

  • 传统的委托方法( UITableViewDelegate )使得在离开之前将自己清除为委托。 这通常是在delegate的dealloc中用otherObject.delegate = nil 。 不这样做是编程错误。 这基本上是你所看到的。 这是代表和委托人寿命基本相同的常见模式。

  • 另一种方法是NSURLConnection如何处理它:保留你的委托,直到你完成。 这个工作的关键是NSURLConnection具有自己的生命周期,所以retain循环将自动工作。 UITableView无法保留其委托,因为这几乎总是会创build一个永久的保留循环。 如果你的物体存在一段时间然后消失,那么这是有道理的。 通常这里委托人的寿命比委托人短得多,所以保留循环不会伤害任何东西。

调用performSelector:withObject:afterDelay:任何对象performSelector:withObject:afterDelay:应始终在自己的dealloc调用cancelPreviousPerformRequestsWithTarget:self 不过,这与您的代表无关。 对象本身应该是自包含的。 (我不知道为什么我一直在想这是真的,然后再次向我自己certificate它不是。当你调用performSelector:… afterDelay:时,你被保留,所以你不能在释放之前释放它。我的SIDE注意,虽然这是真的,这里没有关系。)

SIDE NOTE cancelPrevious...在我的经验中真的很贵。 如果你必须经常打电话给cancelPrvious... ,我build议保留你自己的一次性NSTimer并在火灾发生时重置它以获得相同的效果。 performSelector:withObject:afterDelay:仅仅是一个单次计时器的包装。

我正在回答自己,因为该页面警告我不要在评论中进行扩展讨论… 🙂

好的,所以看起来,我的回答是[self performSelector:withObject:afterDelay:]自动保留我的对象,直到它“开枪射击”,在这一点上,我猜视图控制器死亡。

所以,现在它有道理为什么我的自定义类尝试访问释放的对象,当它试图将其答案返回给它的委托,这是一个__unsafe_unretained对象,这意味着它可以死(我认为)。

我现在想要的是防止这种错误的方法。 在.NET中,我有各种各样的error handling选项来执行此操作,但我无法想到在此处进行故障安全“保护”。

我试过[[self Delegate] isKindOfClass:... ,但不能确定委托将是什么样的类,所以它不会工作。

我也试过[[self Delegate] respondsToSelector:@selector(...)] 。 我不确定为什么会失败,但是我也得到了EXC_BAD_ACCESS。

我不想要的是我的客户能够用这样一个简单的,天真的错误来使我的产品崩溃。

顺便说一下,有没有人知道为什么这种失败给了我如此容易的访问.m文件的内容应该隐藏在我的.a文件内? 我错误地build立了我的图书馆吗?

谢谢!

尝试将代表设置为dealloc中的零。

例:

 self.fetchedResultsController.delegate = nil; 

我最近看到这个问题很多,通常解决这个问题。 即使代表应该是弱引用,有时一些私有实现也在使用它们。

如果我释放,我得到坏访问,如果我保留,我泄漏

那就是我遇到类似问题的地方。

编辑:当使用ARC,你仍然可以覆盖dealloc清理,你只是不能调用[超级dealloc]或释放任何东西。