175

在 Xcode 4.2 中使用自动引用计数 (ARC) 时,如何转换(或创建)一个能够正确编译和运行的单例类?

4

10 回答 10

401

与您(应该)已经这样做的方式完全相同:

+ (instancetype)sharedInstance
{
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[MyClass alloc] init];
        // Do any other initialisation stuff here
    });
    return sharedInstance;
}
于 2011-09-27T12:22:17.980 回答
8

如果您想根据需要创建其他实例。请执行以下操作:

+ (MyClass *)sharedInstance
{
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[MyClass alloc] init];
        // Do any other initialisation stuff here
    });
    return sharedInstance;
}

否则,你应该这样做:

+ (id)allocWithZone:(NSZone *)zone
{
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [super allocWithZone:zone];
    });
    return sharedInstance;
}
于 2013-04-08T09:19:32.140 回答
5

这是 ARC 和非 ARC 的版本

如何使用:

MySingletonClass.h

@interface MySingletonClass : NSObject

+(MySingletonClass *)sharedInstance;

@end

MySingletonClass.m

#import "MySingletonClass.h"
#import "SynthesizeSingleton.h"
@implementation MySingletonClass
SYNTHESIZE_SINGLETON_FOR_CLASS(MySingletonClass)
@end
于 2013-06-07T05:35:29.637 回答
2

这是我在 ARC 下的模式。满足使用 GCD 的新模式,也满足 Apple 旧的实例化预防模式。

@implementation AAA
+ (id)alloc
{
    return  [self allocWithZone:nil];
}
+ (id)allocWithZone:(NSZone *)zone
{
    [self doesNotRecognizeSelector:_cmd];
    abort();
}
+ (instancetype)theController
{
    static AAA* c1  =   nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
    {
        c1  =   [[super allocWithZone:nil] init];

        // For confirm...       
        NSLog(@"%@", NSStringFromClass([c1 class]));    //  Prints AAA
        NSLog(@"%@", @([c1 class] == self));            //  Prints 1

        Class   real_superclass_obj =   class_getSuperclass(self);
        NSLog(@"%@", @(real_superclass_obj == self));   //  Prints 0
    });

    return  c1;
}
@end
于 2013-10-16T09:44:54.060 回答
2

阅读这个答案,然后去阅读另一个答案。

您必须首先知道 Singleton 是什么意思以及它的要求是什么,如果您不理解它,那么您就不会理解解决方案——根本就不会!

要成功创建 Singleton,您必须能够执行以下 3 项操作:

  • 如果存在竞争条件,那么我们不能允许同时创建多个 SharedInstance 实例!
  • 记住并保留多个调用中的值。
  • 只创建一次。通过控制入口点。

dispatch_once_t通过只允许其块被调度一次来帮助您解决竞争条件。

Static帮助您在任意数量的调用中“记住”它的值。它是如何记忆的?它不允许再次创建具有您的 sharedInstance 确切名称的任何新实例,它仅适用于最初创建的实例。

在我们的 sharedInstance 类上不使用调用alloc init(即我们仍然有alloc init方法,因为我们是 NSObject 子类,尽管我们不应该使用它们),我们通过 using 来实现这一点,无论来自不同线程的多次尝试+(instancetype)sharedInstance,它都只能启动一次同时记住它的价值。

Cocoa 自带的一些最常见的系统单例是:

  • [UIApplication sharedApplication]
  • [NSUserDefaults standardUserDefaults]
  • [NSFileManager defaultManager]
  • [NSBundle mainBundle]
  • [NSOperations mainQueue]
  • [NSNotificationCenter defaultCenter]

基本上任何需要具有集中效果的东西都需要遵循某种单例设计模式。

于 2016-04-16T17:29:52.813 回答
1

或者,Objective-C 为 NSObject 及其所有子类提供了 +(void)initialize 方法。它总是在类的任何方法之前调用。

我在 iOS 6 中设置了一次断点,并且 dispatch_once 出现在堆栈帧中。

于 2013-05-20T19:28:47.647 回答
0

接受的答案有两个问题,可能与您的目的相关,也可能不相关。

  1. 如果从 init 方法中,以某种方式再次调用 sharedInstance 方法(例如,因为从那里构造了其他使用单例的对象),它将导致堆栈溢出。
  2. 对于类层次结构,只有一个单例(即:调用 sharedInstance 方法的层次结构中的第一个类),而不是层次结构中的每个具体类一个单例。

以下代码解决了这两个问题:

+ (instancetype)sharedInstance {
    static id mutex = nil;
    static NSMutableDictionary *instances = nil;

    //Initialize the mutex and instances dictionary in a thread safe manner
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        mutex = [NSObject new];
        instances = [NSMutableDictionary new];
    });

    id instance = nil;

    //Now synchronize on the mutex
    //Note: do not synchronize on self, since self may differ depending on which class this method is called on
    @synchronized(mutex) {
        id <NSCopying> key = (id <NSCopying>)self;
        instance = instances[key];
        if (instance == nil) {
            //Break allocation and initialization into two statements to prevent a stack overflow, if init somehow calls the sharedInstance method
            id allocatedInstance = [self alloc];

            //Store the instance into the dictionary, one per concrete class (class acts as key for the dictionary)
            //Do this right after allocation to avoid the stackoverflow problem
            if (allocatedInstance != nil) {
                instances[key] = allocatedInstance;
            }
            instance = [allocatedInstance init];

            //Following code may be overly cautious
            if (instance != allocatedInstance) {
                //Somehow the init method did not return the same instance as the alloc method
                if (instance == nil) {
                    //If init returns nil: immediately remove the instance again
                    [instances removeObjectForKey:key];
                } else {
                    //Else: put the instance in the dictionary instead of the allocatedInstance
                    instances[key] = instance;
                }
            }
        }
    }
    return instance;
}
于 2017-01-02T15:08:54.820 回答
0

单例类:在任何情况下或通过任何方式,没有人可以创建多个类的对象。

+ (instancetype)sharedInstance
{
    static ClassName *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[ClassName alloc] init];
        // Perform other initialisation...
    });
    return sharedInstance;
}
//    You need need to override init method as well, because developer can call [[MyClass alloc]init] method also. that time also we have to return sharedInstance only. 

-(MyClass)init
{
   return [ClassName sharedInstance];
}
于 2016-04-29T02:31:57.430 回答
-2

如果您需要快速创建单例,

class var sharedInstance: MyClass {
    struct Singleton {
        static let instance = MyClass()
    }
    return Singleton.instance
}

或者

struct Singleton {
    static let sharedInstance = MyClass()
}

class var sharedInstance: MyClass {
    return Singleton.sharedInstance
}

你可以用这种方式

let sharedClass = LibraryAPI.sharedInstance
于 2015-08-21T14:57:17.790 回答
-2
#import <Foundation/Foundation.h>

@interface SingleTon : NSObject

@property (nonatomic,strong) NSString *name;
+(SingleTon *) theSingleTon;

@end

#import "SingleTon.h"
@implementation SingleTon

+(SingleTon *) theSingleTon{
    static SingleTon *theSingleTon = nil;

    if (!theSingleTon) {

        theSingleTon = [[super allocWithZone:nil] init
                     ];
    }
    return theSingleTon;
}

+(id)allocWithZone:(struct _NSZone *)zone{

    return [self theSingleTon];
}

-(id)init{

    self = [super init];
    if (self) {
        // Set Variables
        _name = @"Kiran";
    }

    return self;
}

@end

希望上面的代码能帮上忙。

于 2015-08-06T11:48:38.390 回答