Re: Is Apple's singleton sample code correct?
Re: Is Apple's singleton sample code correct?
- Subject: Re: Is Apple's singleton sample code correct?
- From: David Gimeno Gost <email@hidden>
- Date: Thu, 1 Dec 2005 18:27:21 +0100
On 30 Nov 2005, at 02:11, Jeff Laing wrote:
I think whats being suggested by about 30% of the participants in this
thread is that the singleton register itself to listen for the
notifications.
I believe David is *not* suggesting this, but rather that your
application
logic listen for the notification and call an appropriate method on the
singleton to tell it to go away. (Or perhaps have the application
delegate
do it - either approach would work)
Actually I've always had both approaches in mind and I've strived to
not make this explicit until now on purpose. This issue is tough if you
want to consider it from a general point of view, and the level of
misunderstanding in this thread already was high enough.
The real issue here is possible cleanup dependencies. Resources may
need to be disposed of in a certain order. An object managing certain
resources may depend on the services provided by another object to do
its own cleanup.
If I've correctly understood the way notifications work, you have
little or no control at all over the order in which they will be
received. That means that if you have two objects that have registered
for the notification and one of them depends on the other to do its job
first, then you are in trouble. Also, you may not like the idea of
having to add notification registering and handling to every object
whose resources must be properly disposed of.
So you may want to centralize all notification registering and handling
for application termination in a single object (e.g. the application
delegate). But this approach has its own share of problems as well. The
method responsible for scheduling the cleanup becomes coupled with
object dependencies it probably shouldn't have to be aware of. Also,
the object responsible to do the cleanup may be a singleton that you
don't (and shouldn't have to) know whether it has actually been
instantiated or not.
So, in the general case, you have to consider both approaches (maybe in
the same application) and handle both of them properly.
It is true that using [singleton release] instead of [singleton
doCleanUp]
is more sensitive to coding problems elsewhere in your application -
but if
you are going to argue that sort of theoretical scenario, what happens
to
the objects that have erroneously retain'd the singleton if they try to
access it *after* the doCleanUp message was delivered - which they
might do
during their own cleanup processing?
Actually, I would say it's the other way around. The only things you
should be concerned with using the [singleton release] approach are the
same things you would be concerned with if the singleton was an
ordinary object, namely adherence to memory management rules and cyclic
references. The retain/release facilities provided by the framework
provide a consistent and uniform approach to handle cleanup
dependencies as any other dependency. With the [singleton doCleanUp]
approach, you have to separately take care of cleanup dependencies
yourself.
Consider, for example, the (supposedly problematic) case when sending
[singleton release] wouldn't actually deallocate the singleton because
some other object still keeps a (retained) reference to it. What this
means (or should mean, if there is no bug) is that the object that
retains the singleton actually depends on the singleton "being there"
for whatever it does. Now, what happens if this object actually needs
the singleton to do its own cleanup? Someone must ensure that neither
the singleton itself nor the resources it manages are released before
this object does its own cleanup. But who? And more important, why? Why
should that extra level of coupling be added when retain/release would
get you this for free?
Sending [singleton release] when the singleton is being retained by
some other object is not the problem, it's the solution. The problem is
that some other object still needs the singleton (and its resources)
and you don't (shouldn't have to) know whether that other object
actually depends on the singleton (and its resources) being there to do
its own cleanup.
Because of the absence of runtime support mechanisms for automatic
handling of object dependencies, for the above to work properly you
must make object dependencies explicit by sending the appropriate
-retain/-release messages when such dependencies exist, even if you
know that the object is a singleton.
Note that this is not a limitation of the [singleton release] approach.
If there is indeed a cleanup dependency, with the [singleton doCleanUp]
approach you'll have to devise your own retain/release-equivalent
mechanism to handle it as well. You can look at the -release message as
a deferred -doCleanUp message. Note also that the memory management
rules explicitly say that you _must_ retain any instance returned by
+sharedInstace if you need to count on the instance "being there"
outside the scope of the method that called +sharedInstace.
"Apple say you should not release something you didn't
{alloc|retain}"
As such, the external request to "cleanup" really shouldn't be done via
release, if you are trying to play by the memory usage rules.
#if !RUNTIME_SYSTEM_HAS_GARBAGE_COLLECTOR
[[MySingleton sharedInstance] release];
#endif
This makes it explicit that you know what you are doing, that the
reason you're doing it is a limitation of the runtime system and that
this code can safely be removed when (and if) the limitation gets
fixed.
By doing things such as this, you become less dependent on the
limitations of the development environment. You can leverage
universally applicable design patterns and idioms you've learned in
other environments which didn't have such limitations. Moreover, your
code is ready to take advantage of the removal of such limitations as
soon as they get fixed. This does not preclude you from taking
advantage of any advanced cutting-edge features that your development
environment might actually have. It's the limitations that you should
avoid your design to be tied to.
Note: I was considering the centralized cleanup scheduling case here,
which means either you know that the singleton has indeed been
instantiated or you have some way of knowing without actually
instantiating it (e.g. the singleton class has a +hasBeenInstantiated
method).
Regards.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden