我正在编写一个库(iPhone 的 Obj-C),我想打包并出售它,所以我显然需要在将其出售之前解决所有设计问题。我还利用这个库来帮助我开发另一个应用程序。
我的库很大程度上建立在任务委派的基础上。我的主要功能是启动一个(可能)长时间运行的进程,完成后,我在类的委托中调用委托协议方法。
这里的另一个复杂因素是,我经常安排此任务每 30 秒左右触发一次。通常,我使用 [self PerformSelector:@selector(someMethod:) withObject:nil afterDelay:30] 而不是使用 NSTimer 来执行此操作。然后,当委托方法成功返回时,我处理返回的数据并在另外 30 秒后触发该方法。这让我在方法调用之间有 30 秒的时间,而不是从一个调用开始到下一个调用之间的时间为 30 秒。 (这主要是为了防止调用时间超过 30 秒,这种情况不应该发生。)
我捕获的错误是,有时委托回调方法会因 EXC_BAD_ACCESS 错误而失败。根据我的调查,自从长时间运行的进程启动以来,我的类库的委托似乎已经消失(已释放/解除分配)。因此,当它调用 [[self Delegate] doSomeDelegateMethod] 时,它正在访问一个已释放的对象。
我尝试首先检查 [[self Delegate] respondsToSelector:@selector(doSomeDelegateMethod)],但即使该访问显然也会引发 EXC_BAD_ACCESS。
检查 [self Delegate] == nil 似乎也不是正确的方法。
在这个特定的实例中,我认为我已经解决问题的一种方法是,当实例化我的对象的视图控制器消失时(因此在前往垃圾转储的路上),我调用 [NSObject cancelPreviousPerformRequestsWithTarget:self]。这显然解决了问题。 (这个“修复”是否也表明我的对象“知道”即将到来的呼叫并将其自身保留在内存中,直到它能够成功地、绝望地发射最后一枪?)
这看起来像是在枪伤上贴了创可贴。是的,这一次似乎阻止了我的应用程序崩溃,但我的直觉告诉我,这是一个糟糕的解决方案。
我还考虑过在 viewWillDisappear:animated: 方法中将自定义对象设置为 nil,这可能是正确的编码模式,但客户必须如此精确地处理我的对象似乎并不正确。
然而,真正困扰我的是,作为一个库开发人员,我还没有找到一种方法来“装箱”我的代码,这样如果用户不执行以下操作,它就不会抛出异常正确的事情。基本上,我想要一种方法来获得我的对象:
- 获取请求。
- 去寻找答案吧。
- 找到答案。
- 尝试返回答案。
- 意识到另一端没有任何东西。
- 放弃并自行死亡。 (好吧,所以“自己死”可能不会发生,但你明白了。)
一个有趣的侧面:
我防止此类错误发生的主要原因是:
我执行了以下步骤:
- 构建了我的库的 .h/.m 文件。
- 生成我的库的 .a 输出文件。
- 将我的库的 .a/.h 文件导入到另一个项目中。
- 出现上述错误。
- 必须仔细阅读应该隐藏在 .a 文件中的 .m 文件之一的代码。
我在这里错过了什么吗?如果我的整个源代码向客户端抛出错误,我真的会冒暴露整个源代码的风险吗? (这只是一个次要问题,但我在这里相当担心!)
感谢您提供的任何帮助,帮助我成为一名更好的程序员!
- -编辑 - -
我发现了另一个重要的原因。在另一个视图控制器中,我使用这个库,我实现了 NSTimer 策略。如果视图从导航堆栈中弹出(即在 viewWillDisappear:animated: 方法中),我将使所述计时器无效。因此,视图消失后,不会再有任何调用进入我的库。
问题是:如果视图消失怎么办?在中间长时间运行的调用?是的,这很棘手而且不太可能做到,但我只是在模拟器上发生了这种情况。尤其,THIS这就是为什么我正在寻找一种解决方法,让我的代码意识到“嘿,这个管道的另一端没有任何东西”,然后优雅地失败。任何人?
Thanks!