如果你的目标系统是iOS 4.0或以上

使用GCD,它是在Objective-C(线程安全)中创建单例的最好方法吗?

+ (instancetype)sharedInstance
{
    static dispatch_once_t once;
    static id sharedInstance;
    dispatch_once(&once, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

当前回答

你问这是否是“创建单例的最佳方式”。

以下是一些想法:

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.

其他回答

要创建线程安全单例,你可以这样做:

@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

这个博客很好地解释了objc/cocoa中的单例

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
@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;
}

如果你想确保[[MyClass alloc] init]返回与sharedInstance相同的对象(在我看来没有必要,但有些人想要它),可以使用第二个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.

+sharedInstance方法将像往常一样工作。如果它不是第一个调用[[MyClass alloc] init]的调用者,那么init的结果不是alloc调用的结果,但这是可以的。

可以避免通过覆盖alloc方法来分配类。

@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;
}