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: Ondra Cada <email@hidden>
- Date: Tue, 29 Nov 2005 10:17:01 +0100
David,
On 29.11.2005, at 0:51, David Gimeno Gost wrote:
Lets at least adhere to the conventions of the memory management
provided by the framework, whether singleton or not.
More or less all others are trying to point out to you that's
exactly what the overriding of memory management methods achieves.
No, overriding those methods does not achieve that. There is no
need to override those methods to achieve that.
There is.
Presume we, for any godforsaken reason, *need* that the singleton
contract ("there is at most one") is fulfilled even if it happens to
be accessed through the standard alloc/init combo (note please I do
not advocate we need this all the time, quite the contrary -- I say
we need that pretty rarely, but we may).
If so, we just have to re-implement alloc, init, or both -- for
obvious reasons.
Presume further we don't want the singleton to die at all (or, at the
very least, not till the application is about to quit -- I'll get
back to it in a moment). Again, of course, it may not be the case
with some particular singleton class; nevertheless, in my experience,
this would be normally (though of course not always) exactly what we
need: more often than not the singleton, along with other tasks,
keeps some settings and values which, once set up, should not vanish
before the application quits (and not all of them belong to the
default database or other external storage, either). Sure, you can
store them in statics: ugly design, quite non-necessary, caused only
by the original design flaw (i.e., letting the singleton to die
whilst the app lives on).
So in this case, we have to mess up the retain/release/dealloc combo
too(*), lest the only one who happened to alloc/init the singleton
releases it, and the thing goes poof -- far before we may need it again.
(*) Of course, can be done also without overriding retain/release/
dealloc e.g. by overretaining in init. For all practical reasons
that's exactly the same.
What I am aiming at is *this is what we have to do to adhere to Cocoa
memory-management conventions*, whilst keeping the immortable
singleton contract as well.
You get the correct behavior by just requiring client code to
follow Cocoa's memory management rules.
No you don't. Correct client would first alloc/init the singleton,
then release it. Unless someone other did the same, and unless we did
some trick singleton-level (be it reimplementation of retain/release/
dealloc or overretaining or whatever), the singleton goes poof.
That's *not* what we wanted: we want it to survive infinitely (or at
the very least till app is about to quit).
Actually, overriding those methods allows client code to break
Cocoa's memory management rules without a hitch.
Sure it allows. *So what*? The memory management rules (heck, *any*
reasonable rules in the wide world!) just say: do it this way, and
it's all right. There is ***no*** contract which says that if you do
it otherwise, the app would crash.
(The most obvious example is a forgotten (auto)release: that is a
violation of the memory management rules all right, but the
application runs without a glitch; it leaks memory a bit, but unless
the object in question is big or tooo many of them and/or the app
runs for a long long time, nobody ever notices.)
Back to business: making the class to adhere to memory management
rules means exactly this:
** if the client follows the rules, the class does exactly what we
want it to do **
Namely: singleton is created on demand the first time, shared the
next time, and never dies. [*] Without overriding retain/release/
dealloc (or other trick with the same outcome) it would not apply. In
other words, our singleton *would not* adhere to the memory
management rules. [*]
(Note that it's not a bug per se -- many singletons do not, since
their programmers just know they won't be used the standard way.
That's quite another story.)
And note that at least in theory we don't give a tinker's cuss what
happens if the client does *not* follow the rules. Sure, it may be
worth to get defensive, protoect before the more frequent bugs
(overreleasing comes to mind) at least by logging out something like
"If you see this log, put a breakpoint to fooBarOverReleased to see
what's wrong". But again, that's another story, which is *completely*
irrelevant to singletons.
+sharedInstance { static id myself=nil; if (!myself) myself=[[self
alloc] init]; return myself; }
That's a very valid *singleton* we just made here. It does not
quite adhere to the memory-management conventions though, or
rather, it does, alas breaking so the contract of being a
singleton :)
It doesn't? Why?
Since [*] ... [*] above.
Anyway, to use the *object deallocation* tool -- the dealloc
method -- for the *application quit clean-up* -- is plain wrong.
You are just using a completely inappropriate tool;
Why?
Most often than not, disposal of resources should be decoupled from
application quit cleanup. App-quit cleanup is one possible reason
certain resources must be disposed of in a certain way, but it may
not be the only one. Moreover, you don't want to have to know
whether it's the only one. The object that manages the resources
shouldn't be concerned with the reasons those resources should be
disposed of. All the object should be concerned with is that it is
no longer needed (for whatever reasons) and, thus, the resources it
manages should be disposed of properly.
Not quite. There are different kinds of resources, and they are to be
released a different way in different moments. For example, it is
completely nonsensical to release the memory when the process is
about to end.
This is what -dealloc accomplishes. You just tell the object that
manage the resources that you no longer need it.
That's nice from the theoretical point of view. In practice though,
it brings more problems than advantages.
app-quit cleanup is a very very different beast from object
deallocation.
And 'for' loops also are a very different beast, but that doesn't
mean you shouldn't use them to do the cleanup, does it?
It does, for HOM is better :D
Analogically, whilst you *can* tweak dealloc to do your application
termination cleanup, you should not. It's ugly, error-prone, it makes
maintenance a bitch. If I want to see what exactly my application
with hundreds of source files in a number of lodable bundles and
subprojects does before quit, I grep for
NSApplicationWillTerminateNotification, and that's that. What would
you do, check *all* them deallocs, whether some of them may contain
more code than plain [ivar release]?
There is nothing wrong about _using_ object deallocation to do the
app-quit cleanup.
There's all wrong with it. I did it, long ago. I've learnt the hard way.
Disposal of resources by means of the destruction of the objects
that manage them is a well-known widely-used design pattern in
object oriented software development (not just C++).
Incidentally, C++ and object oriented are two things with nothing in
common :)
---
Ondra Čada
OCSoftware: email@hidden http://www.ocs.cz
private email@hidden http://www.ocs.cz/oc
_______________________________________________
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