如何在使用Xcode 4.2的自动引用计数(ARC)时转换(或创建)一个编译并可以正确运行的单例类?
如何在使用Xcode 4.2的自动引用计数(ARC)时转换(或创建)一个编译并可以正确运行的单例类?
以与你之前应该一样的方式:
+ (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;
}
static
变量与在方法/函数外声明的static
变量相同,只是它们只在该方法/函数的范围内有效。每次通过+sharedInstance
方法(即使在不同的线程上)运行,都将“看到”相同的sharedInstance
变量。 - Nick Forge+alloc~
方法以完全防止外部实例化。我已经在答案中发布了一个示例。 - eonil+ (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;
}
dispatch_once()
这一部分意味着即使在第一个示例中,您也不会获得其他实例...? - OlieallocWithZone:
以防止创建更多实例,你还应该重写 init
以防止共享实例被重新初始化。 - jscs使用方法:
MySingletonClass.h
@interface MySingletonClass : NSObject
+(MySingletonClass *)sharedInstance;
@end
MySingletonClass.m
#import "MySingletonClass.h"
#import "SynthesizeSingleton.h"
@implementation MySingletonClass
SYNTHESIZE_SINGLETON_FOR_CLASS(MySingletonClass)
@end
这是我在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
c1
成为 AAA
超类的实例吗?你需要在 self
上调用 +alloc
,而不是在 super
上。 - Nick Forge-allocWithZone:
方法只是一个简单的链到运行时分配函数的方法,以提供重载点。因此,最终,self
指针 == 当前类对象将被传递给分配器,最终 AAA
实例将被分配。 - eonilsuper
在类方法中的微妙之处。 - Nick Forge阅读这个答案,然后去阅读另一个答案。
如果你不理解Singleton是什么以及它的要求,那么你根本不会理解解决方案!
要成功创建Singleton,您必须能够执行以下3个操作:
dispatch_once_t
通过只允许其块被调度一次来帮助您解决竞争条件问题。
{{link2:静态
}}可帮助您在任意数量的调用中“记住”其值。 它如何记住? 它不允许再次创建具有相同名称的新实例,而是仅使用最初创建的实例。
alloc
init
(即使我们仍然有alloc
init
方法,因为我们是NSObject子类,但我们不应该使用它们)在我们的sharedInstance类上,我们通过使用+(instancetype)sharedInstance
来实现这一点,它仅限于被初始化一次,无论多个线程同时尝试多次,都会记住其值。[UIApplication sharedApplication]
[NSUserDefaults standardUserDefaults]
[NSFileManager defaultManager]
[NSBundle mainBundle]
[NSOperations mainQueue]
[NSNotificationCenter defaultCenter]
另外,Objective-C为NSObject及其所有子类提供了+(void)initialize方法。它总是在类的任何方法之前调用。
我曾在iOS 6中设置一个断点,在堆栈帧中出现了dispatch_once。
单例模式:无论任何情况或途径,都不能创建多个类对象。
+ (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];
}
已经有一个已接受的答案,但它可能与您的目的相关或不相关,其中存在两个问题:
以下代码解决了这两个问题:
+ (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;
}
如果你需要在Swift中创建单例,
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
#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
希望上述代码能帮到您。