Ver*_*erd 6 singleton objective-c ios
我知道这有几个主题,但没有人回答我的问题.
我已经像这样实现了我的单例类(了解有关单身人士的争议):
+ (MyClass*) sharedInstance {
static MyClass *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[MyClass alloc] init];
});
return _sharedInstance;
}
- (instancetype)init{
self = [super init];
if (self) {
//setup code
}
return self;
}
Run Code Online (Sandbox Code Playgroud)
我尝试实例化一个不同的对象,并将它与sharedInstance返回的'=='进行比较,它们确实不同.
问题:
CRD*_*CRD 13
您的观察是正确的,您在Objective-C中看到的许多"单例"模式根本不是单例,而是"共享实例"模型,其中可以创建其他实例.
在旧的MRC时代,Apple曾经有过示例代码,展示了如何实现真正的单例.
您拥有的代码是ARC和线程安全单例的推荐模式,您只需将其放在init方法中:
- (instancetype) init
{
static MyClass *initedObject;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
initedObject = [super init];
});
return initedObject;
}
Run Code Online (Sandbox Code Playgroud)
此代码将确保只有一个实例,MyClass无论有多少[MyClass new]或[[MyClass alloc] init]调用.
这就是你需要做的,但你可以走得更远.首先,如果您希望有一个类方法来返回单例,那么它就是:
+ (instancetype) singletonInstance
{
return [self new];
}
Run Code Online (Sandbox Code Playgroud)
此方法最终调用init返回单例,并在需要时创建它.
如果是MyClassimplements,NSCopying那么你还需要实现copyWithZone:- 这是copy调用的方法.你有一个单身人士,这很简单:
- (instancetype) copyWithZone:(NSZone *)zone
{
return self;
}
Run Code Online (Sandbox Code Playgroud)
最后,在Objective-C中,分配新对象实例并对其进行初始化的操作是不同的.上述方案确保只MyClass初始化和使用一个实例,但是每次调用new或alloc另一个实例都被分配,然后init由ARC 迅速丢弃并清理.这有点浪费!
这可以通过实现allocWithZone:(copy如上所述方法alloc实际上最终调用)通过以下相同模式实现init:
+ (instancetype) allocWithZone:(NSZone *)zone
{
static MyClass *allocatedObject;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
allocatedObject = [super allocWithZone:zone];
});
return allocatedObject;
}
Run Code Online (Sandbox Code Playgroud)
第一次创建实例然后allocWithZone:将分配它然后init将其初始化,所有后续调用将返回已存在的对象.没有丢弃不需要的分配.
就是这样,一个真正的单身人士,并没有比如此常见的人造单身人士更难.
HTH
您不能将该init方法设为私有,就像使用构造函数在Java中一样.所以没有什么可以阻止你调用[[MyClass alloc] init]确实创造了一个不同的对象.只要您不这样做,但坚持使用该sharedInstance方法,您的实现就可以了.
你可以做什么:让init方法引发一个异常(例如with [self doesNotRecognizeSelector:@_cmd])并以不同的方法(例如privateInit)执行初始化,该方法未在头文件中公开.
使用objective-c,您可以防止您的单例类创建多个对象。您可以使用单例类阻止 alloc 和 init 调用。
#import <Foundation/Foundation.h>
@interface SingletonClass : NSObject
+ (id) sharedInstance;
- (void) someMethodCall;
- (instancetype) init __attribute__((unavailable("Use +[SingletonClass sharedInstance] instead")));
+ (instancetype) new __attribute__ ((unavailable("Use +[SingletonClass sharedInstance] instead")));
@end
#import "SingletonClass.h"
@implementation SingletonClass
+ (id) sharedInstance{
static SingletonClass * sharedObject = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedObject = [[self alloc] initPrivate];
});
return sharedObject;
}
- (instancetype)init {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"You can't override the init call in class %@", NSStringFromClass([self class])] userInfo:nil];
}
- (instancetype)initPrivate {
if (self = [super init]) {
}
return self;
}
- (void) someMethodCall{
NSLog(@"Method Call");
}
@end
Run Code Online (Sandbox Code Playgroud)
1# 如果您尝试在 SingletonClass 上调用 init 或 new 方法,那么这些方法将无法调用。
2#如果您在头文件中注释掉下面提到的方法并尝试在 SingletonClass 方法上调用 init ,那么应用程序将因“您无法覆盖类 SingletonClass 中的 init 调用”而崩溃。
- (instancetype) init __attribute__((unavailable("Use +[SingletonClass sharedInstance] instead")));
+ (instancetype) new __attribute__ ((unavailable("Use +[SingletonClass sharedInstance] instead")));
Run Code Online (Sandbox Code Playgroud)
只需使用此代码为单例模式创建单个对象,并防止来自其他类的单例模式的 alloc init 调用。我已经用 xCode 7.0+ 测试过这段代码并且它工作正常。
| 归档时间: |
|
| 查看次数: |
3382 次 |
| 最近记录: |