• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Is Apple's singleton sample code correct?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Is Apple's singleton sample code correct?


  • Subject: Re: Is Apple's singleton sample code correct?
  • From: David Gimeno Gost <email@hidden>
  • Date: Sat, 26 Nov 2005 16:21:44 +0100

mmalcolm crawford <email@hidden> wrote:

Can you point me to any document describing the singleton design
pattern saying that a singleton should never be deallocated or
destroyed?

<http://developer.apple.com/cgi-bin/search.pl? q=singleton&site=default_collection>

I already did that search before starting this discussion and I haven't found anything there stating that a singleton should never be deallocated. Actually, I would consider it a bug if I found it because there is nothing in the singleton design pattern requiring it to never be destroyed and there are indeed reasons why you may want to actually be allowed to destroy it when appropriate.


<http://developer.apple.com/documentation/Cocoa/Conceptual/
CocoaDesignPatterns/Articles/HowCocoaAdaptsDP.html>

What this article says is: "Using the shared instance returned by a singleton class is no different from using an instance of a non-singleton class, except that you are prevented from copying, retaining, or releasing it". This is under the "Framework Classes" heading, not in the general description of the pattern.


I take it as saying that the singletons provided by Cocoa are designed to never be deallocated. That's fine, I have no problems with that. But if you are saying that I must take it as meaning that preventing the singleton to be deallocated is part of the design pattern then I would consider it a bug in the documentation because there is nothing in the singleton pattern, as it is widely known, that requires it to never be deallocated. Moreover, as a general rule, I would even say that it _should_ be deallocated when the program ends if for no other reason because the resources it manages may need to be properly released.

That the particular adaptation of the singleton pattern made in the Cocoa frameworks does not allow for their singletons to be deallocated does not change what I'm saying in any way. You may have all the variations of the pattern that you see fit your particular needs. But they are variations, they are not part of the pattern as it is widely known.

But you don't need to override the methods to accomplish that. What
I'm saying is that the default (inherited) methods already do the
right job if users of the class follow the Cocoa's memory
management rules.

This is not the case. If you didn't override release, then (following Cocoa's memory management rules):

MyGizmoClass *gizmo = [[MyGizmoClass alloc] init];
// do some stuff
[gizmo release];

// do some more stuff

MyGizmoClass *gizmo2 = [[MyGizmoClass alloc] init];
[gizmo2 doSomething];  // crash

At this point, sharedGizmoManager is a pointer to a freed object.

Not if +allocWithZone: is written as I later suggested in the same e-mail you are responding to here. Note the added -retain message sent to the shared instance if it already exists:


+ (id) allocWithZone: (NSZone*) zone
{
    @synchronized( self ) {
        if ( sharedGizmoManager == nil ) {
            sharedGizmoManager = [super allocWithZone: zone];
        } else {
            [sharedGizmoManager retain];
        }
    }
    return sharedGizmoManager;
}

2. The -retain and -release methods shouldn't be overridden. There
is no point in doing so and the way it is done in the current
sample code guarantees that code breaking Cocoa's memory management
rules will go by unnoticed.

The whole point of a singleton object is that, if it is created, it
remains valid for the remainder of the lifetime of the application.

The whole point of the singleton is that there is at most one instance of it. The lifetime of the object is not part of the pattern. You may choose to create it at program startup or only when needed. You may choose to destroy it when the resources it manages are no longer needed, or when the program exits, or never destroy it at all. These are all design issues and implementation details that must be considered. They are not requirements. I've yet to come across a reference document that says preventing the singleton from being destroyed is part of the pattern.


It just happens that it is appropriate for most singletons to remain valid for the lifetime of the application, but even that doesn't mean the singleton shouldn't be allowed to be deallocated, because, as a general rule, it should at least be possible to deallocate it when the application quits. And you don't need to do anything special to ensure that. The only requirement is that both the singleton implementation and the code that uses it must adhere to Cocoa's memory management rules. Letting the default -retain and -release methods do their job allows for all lifetime variations of the pattern. There is no need to allow only a single variation that happens to be wrong for singletons that manage resources that should be properly released and that has the side effect of hiding buggy client code that doesn't follow the memory management rules.

Overriding the retain and (in particular) release methods means that
(as Shawn suggested) a developer can continue to adhere to the normal
rules of memory management without needing to "special case" any
objects.  This typically simplifies things.

You don't need to consider them a "special case" if you don't want to. If you want client code to be able to invoke [[alloc] init], and retain/release them as any other object just make sure that your implementation of +allocWithZone: remains consistent with those requirements (by retaining an already existing instance the caller is expected to release later).


This is what really simplifies things because (1) it puts the solution where the problem is located (in the +allocWithZone: method), rather than spreading it over several methods, (2) it will work correctly regardless of whether you choose to override those additional methods or not, i.e. you don't have to override them if you don't have a (another) good reason to do so, (3) it doesn't arbitrarily impose a lifetime requirement on the singleton that may not be appropriate in some cases, and (4) it lets bugs in the memory management of client code be detected during development and testing.

Sample code should strive to be applicable to as many variations as possible while still remaining as clear and simple as possible. The implementation I'm proposing achieves both objectives, the current sample code provided by Apple achieves neither.

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


  • Follow-Ups:
    • Re: Is Apple's singleton sample code correct?
      • From: Shawn Erickson <email@hidden>
    • Re: Is Apple's singleton sample code correct?
      • From: Shawn Erickson <email@hidden>
  • Prev by Date: Re: Is Apple's singleton sample code correct?
  • Next by Date: Re: Is Apple's singleton sample code correct?
  • Previous by thread: Re: Is Apple's singleton sample code correct?
  • Next by thread: Re: Is Apple's singleton sample code correct?
  • Index(es):
    • Date
    • Thread