ChatGPT解决这个技术问题 Extra ChatGPT

Create singleton using GCD's dispatch_once in Objective-C

If you can target iOS 4.0 or above

Using GCD, is it the best way to create singleton in Objective-C (thread safe)?

+ (instancetype)sharedInstance
{
    static dispatch_once_t once;
    static id sharedInstance;
    dispatch_once(&once, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}
Is there a way to prevent users of the class from calling alloc/copy?
dispatch_once_t and dispatch_once appear to have been introduced in 4.0, not 4.1 (see: developer.apple.com/library/ios/#documentation/Performance/…)
This method becomes problematic if init requires use of the singleton object. Matt Gallagher's code has worked for me on more than a few occasions. cocoawithlove.com/2008/11/…
I know its inconsequential in this example; but why don't people use 'new' more. dispatch_once(&once, ^{sharedInstance=[self new];} just looks that bit neater. It's equivalent to alloc+init.
Be sure to start using the return type instancetype. Code completion is much better when using that instead of id.

D
Dave DeLong

This is a perfectly acceptable and thread-safe way to create an instance of your class. It may not technically be a "singleton" (in that there can only ever be 1 of these objects), but as long as you only use the [Foo sharedFoo] method to access the object, this is good enough.


How do you release it though?
@samvermette you don't. the point of a singleton is that it will always exist. thus, you don't release it, and the memory gets reclaimed with the process exits.
@Dave DeLong: In my opinion purpose of having singleton is not a certainty of its immortality, but certainty that we have one instance. What if that singleton decrement a semaphore? You can't just arbitrary say that it will always exists.
@hooleyhoop Yes, in its documentation. "If called simultaneously from multiple threads, this function waits synchronously until the block has completed."
@WalterMartinVargas-Pena the strong reference is held by the static variable
C
Community

instancetype

instancetype is just one of the many language extensions to Objective-C, with more being added with each new release.

Know it, love it.

And take it as an example of how paying attention to the low-level details can give you insights into powerful new ways to transform Objective-C.

Refer here: instancetype

+ (instancetype)sharedInstance
{
    static dispatch_once_t once;
    static id sharedInstance;

    dispatch_once(&once, ^
    {
        sharedInstance = [self new];
    });    
    return sharedInstance;
}

+ (Class*)sharedInstance
{
    static dispatch_once_t once;
    static Class *sharedInstance;

    dispatch_once(&once, ^
    {
        sharedInstance = [self new];
    });    
    return sharedInstance;
}

amazing tip, thanks! instancetype is a contextual keyword that can be used as a result type to signal that a method returns a related result type. ... With instancetype, the compiler will correctly infer the type.
It's not clear to me what the two snippets mean here, are they equivalent to each other? One is preferable to the other? Would be nice if the author can add a bit explanations for this.
S
Sergey Petruk

MySingleton.h

@interface MySingleton : NSObject

+(instancetype)sharedInstance;

+(instancetype)alloc __attribute__((unavailable("alloc not available, call sharedInstance instead")));
-(instancetype)init __attribute__((unavailable("init not available, call sharedInstance instead")));
+(instancetype)new __attribute__((unavailable("new not available, call sharedInstance instead")));
-(instancetype)copy __attribute__((unavailable("copy not available, call sharedInstance instead")));

@end

MySingleton.m

@implementation MySingleton

+(instancetype)sharedInstance {
    static dispatch_once_t pred;
    static id shared = nil;
    dispatch_once(&pred, ^{
        shared = [[super alloc] initUniqueInstance];
    });
    return shared;
}

-(instancetype)initUniqueInstance {
    return [super init];
}

@end

How is the init not available? Isn't it at least available for one init?
Singleton should have only one access point. And this point is sharedInstance. If we have init method in *.h file than you can create another singleton instance. This contradicts the definition of a singleton.
@asma22 __attribute__((unavailable()) makes not available for use these methods. If another programmer wants use method marked as unavailable, he gets error
I completely get and I'm happy I learned something new, nothing wrong with your answer, just may be a bit confusing for newbies...
This only works for MySingleton, for example in MySingleton.m i am calling [super alloc]
m
medvedNick

You can avoid that the class be allocated with overwriting the alloc method.

@implementation MyClass

static BOOL useinside = NO;
static id _sharedObject = nil;


+(id) alloc {
    if (!useinside) {
        @throw [NSException exceptionWithName:@"Singleton Vialotaion" reason:@"You are violating the singleton class usage. Please call +sharedInstance method" userInfo:nil];
    }
    else {
        return [super alloc];
    }
}

+(id)sharedInstance
{
    static dispatch_once_t p = 0;
    dispatch_once(&p, ^{
        useinside = YES;
        _sharedObject = [[MyClass alloc] init];
        useinside = NO;
    });   
    // returns the same object each time
    return _sharedObject;
}

This answers my question in the comments above. Not that I'm so much for defensive programming, but...
D
Dave DeLong

Dave is correct, that is perfectly fine. You may want to check out Apple's docs on creating a singleton for tips on implementing some of the other methods to ensure that only one can ever be created if classes choose NOT to use the sharedFoo method.


eh... that's not the greatest example of creating a singleton. Overriding the memory management methods is not necessary.
This is completely invalid using ARC.
Cited document has since been retired. Also, answers which are solely links to external content are generally poor SO answers. At a minimum excerpt relevant portions within your answer. Don't bother here unless you want the old way saved for posterity.
g
gnasher729

If you want to make sure that [[MyClass alloc] init] returns the same object as sharedInstance (not necessary in my opinion, but some folks want it), that can be done very easily and safely using a second dispatch_once:

- (instancetype)init
{
    static dispatch_once_t once;
    static Class *sharedInstance;

    dispatch_once(&once, ^
    {
        // Your normal init code goes here. 
        sharedInstance = self;
    });

    return sharedInstance;
}

This allows any combination of [[MyClass alloc] init] and [MyClass sharedInstance] to return the same object; [MyClass sharedInstance] would just be a bit more efficient. How it works: [MyClass sharedInstance] will call [[MyClass alloc] init] once. Other code could call it as well, any number of times. The first caller to init will do the "normal" initialisation and store the singleton object away in the init method. Any later calls to init will completely ignore what alloc returned and return the same sharedInstance; the result of alloc will be deallocated.

The +sharedInstance method will work as it always did. If it isn't the first caller to call [[MyClass alloc] init], then the result of init is not the result of the alloc call, but that is OK.


R
Rob

You ask whether this is the "best way to create singleton".

A few thoughts:

First, yes, this is a thread-safe solution. This dispatch_once pattern is the modern, thread-safe way to generate singletons in Objective-C. No worries there. You asked, though, whether this is the "best" way to do it. One should acknowledge, though, that the instancetype and [[self alloc] init] is potentially misleading when used in conjunction with singletons. The benefit of instancetype is that it's an unambiguous way of declaring that the class can be subclassed without resorting to a type of id, like we had to do in yesteryear. But the static in this method presents subclassing challenges. What if ImageCache and BlobCache singletons were both subclasses from a Cache superclass without implementing their own sharedCache method? ImageCache *imageCache = [ImageCache sharedCache]; // fine BlobCache *blobCache = [BlobCache sharedCache]; // error; this will return the aforementioned ImageCache!!! For this to work, you'd have to make sure subclasses implement their own sharedInstance (or whatever you call it for your particular class) method. Bottom line, your original sharedInstance looks like it will support subclasses, but it won't. If you intend to support subclassing, at the very least include documentation that warns future developers that they must override this method. For best interoperability with Swift, you probably want to define this to be a property, not a class method, e.g.: @interface Foo : NSObject @property (class, readonly, strong) Foo *sharedFoo; @end Then you can go ahead and write a getter for this property (the implementation would use the dispatch_once pattern you suggested): + (Foo *)sharedFoo { ... } The benefit of this is that if a Swift user goes to use it, they'd do something like: let foo = Foo.shared Note, there is no (), because we implemented it as a property. Starting Swift 3, this is how singletons are generally accessed. So defining it as a property helps facilitate that interoperability. As an aside, if you look at how Apple is defining their singletons, this is the pattern that they've adopted, e.g. their NSURLSession singleton is defined as follows: @property (class, readonly, strong) NSURLSession *sharedSession; Another, very minor Swift interoperability consideration was the name of the singleton. It's best if you can incorporate the name of the type, rather than sharedInstance. For example, if the class was Foo, you might define the singleton property as sharedFoo. Or if the class was DatabaseManager, you might call the property sharedManager. Then Swift users could do: let foo = Foo.shared let manager = DatabaseManager.shared Clearly, if you really want to use sharedInstance, you could always declare the Swift name should you want to: @property (class, readonly, strong) Foo* sharedInstance NS_SWIFT_NAME(shared); Clearly, when writing Objective-C code, we shouldn't let Swift interoperability outweigh other design considerations, but still, if we can write code that gracefully supports both languages, that's preferable. I agree with others who point out that if you want this to be a true singleton where developers can’t/shouldn’t (accidentally) instantiate their own instances, the unavailable qualifier on init and new is prudent.


N
Nayab Muhammad
@interface className : NSObject{
+(className*)SingleTonShare;
}

@implementation className

+(className*)SingleTonShare{

static className* sharedObj = nil;
static dispatch_once_t once = 0;
dispatch_once(&once, ^{

if (sharedObj == nil){
    sharedObj = [[className alloc] init];
}
  });
     return sharedObj;
}

H
Hancock_Xu

To create thread safe singleton you can do like this:

@interface SomeManager : NSObject
+ (id)sharedManager;
@end

/* thread safe */
@implementation SomeManager

static id sharedManager = nil;

+ (void)initialize {
    if (self == [SomeManager class]) {
        sharedManager = [[self alloc] init];
    }
}

+ (id)sharedManager {
    return sharedManager;
}
@end

and this blog explain singleton very well singletons in objc/cocoa


you are linking to an very old article while OP asks for characteristics about the most modern implementation.
The question is about a specific implementation. You just post another implementation. There-for you don't even attempt to answer the question.
@vikingosegundo The asker ask weather the GCD is the best way to create a Thread safe singleton,my answer give another choice.Any wrong?
the asker asks if a certain implementation is thread-safe. he is not asking for options.
R
Rohit Kashyap
//Create Singleton  
  +( instancetype )defaultDBManager
    {

        static dispatch_once_t onceToken = 0;
        __strong static id _sharedObject = nil;

        dispatch_once(&onceToken, ^{
            _sharedObject = [[self alloc] init];
        });

        return _sharedObject;
    }


//In it method
-(instancetype)init
{
    self = [super init];
  if(self)
     {
   //Do your custom initialization
     }
     return self;
}