¿Cómo depuro singletons en Objective-C?

My app contains several singletons (following from este tutorial). I've noticed however, when the app crashes because of a singleton, it becomes nearly impossible to figure out where it came from. The app breakpoints at the main function giving an EXEC_BAD_ACCESS even though the problem lies in one of the Singleton objects. Is there a guide to how would I debug my singleton objects if they were problematic?

preguntado el 28 de agosto de 11 a las 04:08

Singletons aren't special objects. You should be able to debug them like any other object. Put a breakpoint in the methods you think are suspect, or in the accessor for the shared instance (though you won't be able to get that easily if you followed that page's tutorial). -

(However, I just remembered that you're using those hokey macros. They make debugging difficult because the lines of code they incorporate can't have breakpoints put in them. Deep six macros, if nothing else.) -

3 Respuestas

if you don't want to change your design (as recommended in my other post), then consider the usual debugging facilities: assertions, unit tests, zombie tests, memory tests (GuardMalloc, scribbling), etc. this should identify the vast majority of issues one would encounter.

of course, you will have some restrictions regarding what you can and cannot do - notably regarding what cannot be tested independently using unit tests.

as well, reproducibility may be more difficult in some contexts when/if you are dealing with a complex global state because you have created several enforced singletons. when the global state is quite large and complex - testing these types independently may not be fruitful in all cases since the bug may appear only in a complex global state found in your app (when 4 singletons interact in a specific manner). if you have isolated the issue to interactions of multiple singleton instances (e.g. MONAudioFileCache and MONVideoCache), placing these objects in a container class will allow you to introduce coupling, which will help diagnose this. although increasing coupling is normally considered a bad thing; this does't really increase coupling (it already exists as components of the global state) but simply concentrates existing global state dependencies -- you're really not increasing it as much as you are concentrating it when the state of these singletons affect other components of the mutable global state.

if you still insist on using singletons, these may help:

  • either make them thread safe or add some assertions to verify mutations happen only on the main thread (for example). too many people assume an object with atomic properties implies the object is thread safe. that is false.

  • encapsulate your data better, particularly that which mutates. for example: rather than passing out an array your class holds for the client to mutate, have the singleton class add the object to the array it holds. if you truly must expose the array to the client, then return a copy. ths is just basic ood, but many objc devs expose the majority of their ivars disregarding the importance of encapsualtion.

  • if it's not thread safe and the class is used in a mutithreaded context, make the class (not the client) implement proper thread safety.

  • design singletons' error checking to be particularly robust. if the programmer passes an invalid argument or misuses the interface - just assert (with a nice message about the problem/resolution).

  • do write unit tests.

  • detach state (e.g. if you can remove an ivar easily, do it)

  • reduce complexity of state.

  • if something is still impossible to debug after writing/testing with thorough assertions, unit tests, zombie tests, memory tests (GuardMalloc, scribbling), etc,, you are writing programs which are too complex (e.g. divide the complexity among multiple classes), or the requirements do not match the actual usage. if you're at that point, you should definitely refer to my other post. the more complex the global variable state, the more time it will take to debug, and the less you can reuse and test your programs when things do go wrong.

buena suerte

Respondido 29 ago 11, 02:08

I scanned the article, and while it had some good ideas it also had some bad advice, and it should not be taken as gospel.

And, as others have suggested, if you have a lot of singleton objects it may mean that you're simply keeping too much state global/persistent. Normally only one or two of your own should be needed (in addition to those that other "packages" of one sort or another may implement).

As to debugging singletons, I don't understand why you say it's hard -- no worse than anything else, for the most part. If you're getting EXEC_BAD_ACCESS it's because you've got some sort of addressing bug, and that's nothing specific to singleton schemes (unless you're using a very bad one).

Macros make debugging difficult because the lines of code they incorporate can't have breakpoints put in them. Deep six macros, if nothing else. In particular, the SYNTHESIZE_SINGLETON_FOR_CLASS macro from the article is interfering with debugging. Replace the call to this macro function with the code it generates for your singleton class.

Respondido el 06 de Septiembre de 11 a las 07:09

Would you like to elaborate on what in the article constitutes "bad advice"? It would be helpful to those of us who didn't pick up on it. :) - Sedate Alien

Primarily, the advice to essentially never use the app delegate was bad advice. There's basically nothing you can do with a singleton that you can't do with an app delegate, and, if properly structured, the app delegate provides better clarity. An app delegate is appropriate for a "portable" facility, but is unnecessary for the "body" of the app. And the guy spent essentially zero time discussing how to avoid needing globals at all, a topic that merited more discussion. - Lamidas calientes

For an example for EXEC_BAD_ACCESS: I'm accessing an object that hasn't been initialized. Normally without singletons, the debugger would point exactly where I screwed up in the code. But when I access an uninitialized object in a singleton, Xcode simply points to "main". That's why I'm wondering if there's anyway to figure out where my singleton isn't doing something properly. - ninjaneer

The debugger has no idea that it's a singleton. Something else is going on. - Lamidas calientes

@Ninja -- seem my comment above. Using those hokey macros makes debugging harder because the lines generated by the macros aren't debuggable. - Lamidas calientes

ugh - don't enforce singletons. just create normal classes. if your app just one instance, add them to something which is created once, such as your app delegate.

most cocoa singleton implementations i've seen should not have been singletons.

then you will be able to debug, test, create, mutate and destroy these objects as usual.

the good part is course that the majority of your global variable pains will disappear when you implement these classes as normal objects.

Respondido 28 ago 11, 09:08

Though I appreciate the viewpoint, this doesn't address the OP's question, and should be a comment instead. - Ben Zotto

@quixoto 7 minutes before your comment, i added "then you will be able to debug, test, create, mutate and destroy these objects as usual. the good part is course that the majority of your global variable pains will disappear when you implement these classes as normal objects.". imo, this addresses the problem. I admit, the answer may not necessarily be the shortest possible route but (imo) the preferred long term solution in the majority of cases. - Justin

I've been scolded for doing this before (in a professional work environment). Now I'm being scolded for not doing this. Not sure what to do. Either way, this answer isn't exactly helpful. If there's no way to debug these singletons, please say so. - ninjaneer

@Ninja not trying to 'scold' - just writing what i do to avoid these problems (professionally). it's helpful (imo) because a large mutable global state adds a lot of unnecessary complexities which can become very difficult to debug/reproduce. using a singleton is usually done with the intent to reduce complexity - often, it just moves the complexity. anyways, of course you can debug singletons - see my second answer. good luck. - Justin

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.