Objective-C中使用GCD的dispatch_once创建单例

发布于 2024-11-02 01:42:55 字数 318 浏览 1 评论 0原文

如果您可以

使用 GCD 面向 iOS 4.0 或更高版本,那么这是在 Objective-C 中创建单例(线程安全)的最佳方法吗?

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

吃不饱 2024-11-09 01:42:55

这是创建类实例的完全可接受且线程安全的方式。从技术上讲,它可能不是“单例”(因为这些对象中只能有 1 个),但只要您只使用 [Foo sharedFoo] 方法来访问该对象,这就是够好了。

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.

无法回应 2024-11-09 01:42:55

instancetype

instancetype 只是 Objective-C 的众多语言扩展之一,每个新版本都会添加更多语言扩展。

知道它,喜欢它。

并以此为例,说明关注底层细节如何让您深入了解改造 Objective-C 的强大新方法。

请参阅此处: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;
}

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;
}
星星的轨迹 2024-11-09 01:42:55

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

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
酷到爆炸 2024-11-09 01:42:55

您可以通过覆盖 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;
}

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;
}
允世 2024-11-09 01:42:55

戴夫是对的,那很好。您可能需要查看 Apple 关于创建单例的文档,了解实现其他一些方法的提示以确保如果类选择不使用sharedFoo方法,则只能创建一个。

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.

柒七 2024-11-09 01:42:55

如果你想确保[[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;
}

这允许任何[[MyClass alloc] init] 和 [MyClass sharedInstance] 的组合返回相同的对象; [MyClass sharedInstance] 会更高效一些。工作原理: [MyClass sharedInstance] 将调用 [[MyClass alloc] init] 一次。其他代码也可以调用它,任意次数。 init 的第一个调用者将执行“正常”初始化并将单例对象存储在 init 方法中。以后对 init 的任何调用都将完全忽略 alloc 返回的内容并返回相同的共享实例; alloc 的结果将被释放。

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

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.

花间憩 2024-11-09 01:42:55

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

一些想法:

  1. 首先,是的,这是一个线程安全的解决方案。这种 dispatch_once 模式是在 Objective-C 中生成单例的现代、线程安全的方法。不用担心。

  2. 不过,您问这是否是“最佳”方法。不过,应该承认,instancetype[[self alloc] init] 在与单例结合使用时可能会产生误导。

    instancetype 的好处是,它是一种明确的方式来声明该类可以被子类化,而无需求助于 id 类型,就像我们过去必须做的那样.

    但是此方法中的静态带来了子类化挑战。如果 ImageCacheBlobCache 单例都是 Cache 超类的子类,而不实现自己的 sharedCache 方法,该怎么办? p>

    ImageCache *imageCache = [ImageCache共享缓存]; // 美好的
    BlobCache *blobCache = [BlobCache 共享缓存]; // 错误;这将返回前面提到的 ImageCache!!!
    

    为此,您必须确保子类实现自己的 sharedInstance (或您为特定类调用的任何方法)。

    底线,您原来的 sharedInstance 看起来它将支持子类,但事实并非如此。如果您打算支持子类化,至少要包含警告未来开发人员必须重写此方法的文档。

  3. 为了与 Swift 实现最佳互操作性,您可能希望将其定义为属性,而不是类方法,例如:

    @interface Foo : NSObject
    @property(类,只读,强)Foo *sharedFoo;
    @结尾
    

    然后您可以继续为此属性编写一个 getter(实现将使用您建议的 dispatch_once 模式):

    + (Foo *)sharedFoo { ... }
    

    这样做的好处是,如果 Swift 用户要使用它,他们会执行以下操作:

    let foo = Foo.shared
    

    注意,没有 (),因为我们将其实现为属性。从 Swift 3 开始,这就是通常访问单例的方式。因此将其定义为属性有助于促进互操作性。

    顺便说一句,如果你看看苹果是如何定义他们的单例的,这就是他们采用的模式,例如他们的 NSURLSession 单例定义如下:

    @property(类,只读,强)NSURLSession *sharedSession;
    
  4. 另一个非常小的 Swift 互操作性考虑因素是单身人士的名字。最好可以合并类型的名称,而不是 sharedInstance。例如,如果类是 Foo,您可以将单例属性定义为 sharedFoo。或者,如果类是DatabaseManager,您可以调用属性sharedManager。那么 Swift 用户可以这样做:

    let foo = Foo.shared
    让管理器 = DatabaseManager.shared
    

    显然,如果您确实想使用 sharedInstance,您可以随时声明 Swift 名称:

    @property(类,只读,强)Foo*sharedInstance NS_SWIFT_NAME(共享);
    

    显然,在编写 Objective-C 代码时,我们不应该让 Swift 的互操作性凌驾于其他设计考虑之上,但是,如果我们能够编写能够优雅地支持两种语言的代码,那就更好了。

  5. 我同意其他人的观点,他们指出,如果您希望这是一个真正的单例,而开发人员不能/不应该(意外地)实例化他们自己的实例,则 上的 unavailable 限定符>initnew 是谨慎的。

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

A few thoughts:

  1. 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.

  2. 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.

  3. 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;
    
  4. 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.

  5. 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.

记忆消瘦 2024-11-09 01:42:55

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

@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 中的单例< /a>

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

独孤求败 2024-11-09 01:42:55
@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;
}
@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;
}
绿光 2024-11-09 01:42:55
//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;
}
//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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文