如何在Objective-C中调试单例

时间:2011-08-28 04:49:33

标签: objective-c debugging singleton

我的应用包含多个单身人士(来自this tutorial)。然而,我注意到,当应用程序因单例崩溃时,几乎不可能弄清楚它来自何处。主函数的app断点给出了EXEC_BAD_ACCESS,即使问题在于其中一个Singleton对象。是否有指导如何调试我的单例对象?如果它们有问题?

3 个答案:

答案 0 :(得分:1)

如果您不想更改您的设计(如我在其他帖子中所建议的那样),那么请考虑常用的调试工具:断言,单元测试,僵尸测试,内存测试(GuardMalloc,scribbling)等。这应该识别人们会遇到的绝大多数问题。

当然,对于你能做什么和不能做什么,你会有一些限制 - 特别是关于不能使用单元测试独立测试的内容。

同样,在某些情况下,当您处理复杂的全局状态时,由于您创建了多个强制单例,因此可重现性可能更难。当全局状态非常庞大且复杂时 - 在所有情况下独立测试这些类型可能并不富有成效,因为错误可能只出现在应用程序中的复杂全局状态中(当4个单例以特定方式交互时)。如果您已将问题隔离到多个单例实例的交互(例如MONAudioFileCache和MONVideoCache),则将这些对象放在容器类中将允许您引入耦合,这将有助于诊断它。虽然增加耦合通常被认为是坏事;这并没有真正增加耦合(它已经作为全局状态的组件存在),而只是集中了现有的全局状态依赖关系 - 当这些单例的状态影响其他组件时,你实际上并没有增加它的集中度可变的全球状态。

如果你仍坚持使用单身人士,这些可能会有所帮助:

  • 要么使它们线程安全,要么添加一些断言来验证仅在主线程上发生的突变(例如)。太多人认为具有原子属性的对象意味着该对象是线程安全的。这是假的。

  • 更好地封装您的数据,尤其是变异的数据。例如:让您的类保持客户端变异,而不是传递一个数组,让单例类将对象添加到它所拥有的数组中。如果您确实必须将数组公开给客户端,则返回一个副本。这只是基本的东西,但是许多objc devs暴露了他们的大部分伊利亚斯,无视封装的重要性。

  • 如果它不是线程安全的并且该类在mutithreaded上下文中使用,则使类(而不是客户端)实现正确的线程安全。

  • 设计单身人士的错误检查特别健壮。如果程序员传递了无效的参数或者滥用了接口 - 只需断言(带有关于问题/解决方案的好消息)。

  • 写单元测试。

  • 分离状态(例如,如果您可以轻松移除ivar,请执行此操作)

  • 降低国家的复杂程度。

  • 如果在使用彻底的断言,单元测试,僵尸测试,内存测试(GuardMalloc,scribbling)等编写/测试后仍然无法调试某些内容,那么您正在编写过于复杂的程序(例如,除以多个类之间的复杂性),或者要求与实际使用情况不符。如果你在那一点上,你一定要参考我的另一篇文章。全局变量状态越复杂,调试所需的时间就越多,并且在出现问题时重用和测试程序的次数就越少。

祝你好运

答案 1 :(得分:1)

我扫描了这篇文章,虽然它有一些好主意,但它也有一些不好的建议,不应该把它当作福音。

并且,正如其他人所建议的那样,如果你有很多单例对象,那么这可能意味着你只是保持太多状态全局/持久性。通常只需要你自己的一两个(除了那些或其他类型的“包”可以实现的那些)。

关于调试单身人士,我不明白为什么你说这很难 - 在大多数情况下都不比其他任何事情更糟糕。如果您正在获得EXEC_BAD_ACCESS,那是因为您遇到了某种寻址错误,而且这与单例方案无关(除非您使用非常糟糕的方案)。

宏使调试变得困难,因为它们包含的代码行不能包含断点。深六个宏,如果没有别的。特别是,文章中的SYNTHESIZE_SINGLETON_FOR_CLASS宏干扰了调试。将对此宏函数的调用替换为它为单例类生成的代码。

答案 2 :(得分:0)

呃 - 不要强制执行单身人士。只需创建普通类。如果您的应用只需要一个实例,请将其添加到一次创建的内容中,例如您的应用代理。

我见过的大多数可可单身实现不应该是单身

然后您将能够像往常一样调试,测试,创建,变异和销毁这些对象。

当你将这些类作为普通对象实现时,好的部分当然是你的大部分全局变量都会消失。