I don't want an exclusive singleton - that is, there is not only one shared singleton instance, the user can also set up one for their own, like recent versions of NSFileManager on OS X.
Can I do this: // Singleton.m static Singleton *__singleton @implementation Singleton + (instancetype)sharedSingleton { @synchronized (__singleton) { if (!__singleton) __singleton = [[self alloc] init]; } return __singleton; } // … @end 在 2013-6-7,下午4:26,David Chisnall <david.chisn...@cl.cam.ac.uk> 写道: > On 7 Jun 2013, at 07:29, Maxthon Chan <xcvi...@me.com> wrote: > >> Just asking, with ARC, is this a good choice on implementing singleton? > > No, it's not thread-safe. > >> //Singleton.h >> #import <Foundation/Foundation.h> >> @interface Singleton : NSObject >> + (instancetype)defaultSingleton; >> // … >> @end >> extern Singleton *DefaultSingleton // Of course this is optional >> >> // Singleton.m >> Singleton *DefaultSingleton > > This should be declared static, as the variable should not be exposed outside > of the Singleton.m compilation unit. > >> @implementation Singleton >> + (instancetype)defaultSingleton >> { >> if (!DefaultSingleton) >> DefaultSingleton = [[self alloc] init]; > > If two threads call this method at once, then both will enter the body of > this if statement, both will allocate instances of the singleton and one > version will leak. > > The correct way of implementing a singleton is to create it in the > +initialize method, which is guaranteed to be thread-safe. My preferred > pattern is: > > + (void)initialize > { > [[self alloc] init]; > } > + allocWithZone: (NSZone*)aZone > { > if (DefaultSingleton != nil) > { > [NSException raise: NSInvalidArgumentException format: > @"Attempted to create multiple instances of singleton %@", self]; > } > DefaultSingleton = [super allocWithZone: aZone]; > NSAssert(nil != DefaultSingleton, @"Allocation of singleton instance of > %@ failed!", self); > return DefaultSingleton; > } > > Calling the constructor in +initialize means that the first time ANY message > is sent to this class, the singleton will be created and no other thread will > be allowed to send messages to this class until the singleton is fully > initialised. > > The nil check in +allocWithZone: is safe, because the variable will be set > with a lock held and can then be safely queried because it will never > transition from non-nil to nil. This exception prevents people from calling > +alloc on the object. > > Assigning the value to DefaultSingleton in +allocWithZone: instead of > +initialize means that calls to things from the -init method don't have to > have special cases to check the presence of the singleton. > > For completeness, you may also include NSCoding methods that ensure that the > singleton is correctly created when serialising / deserialising. It would be > nice if there were an NSSingleton protocol that included a +sharedInstance > method so that the serialiser code could know to always replace any > references to the class with the shared instance, but there isn't. > > David > _______________________________________________ Gnustep-dev mailing list Gnustep-dev@gnu.org https://lists.gnu.org/mailman/listinfo/gnustep-dev