ImH*_*its 6 singleton objective-c
在阅读了对Objective C中关于单例的问题的回答之后,似乎每个解决方案都在实例访问器中对线程进行了一些权衡.即
@synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
Run Code Online (Sandbox Code Playgroud)
这基本上是单线程访问单例,如果它是在操作中经常使用的东西,看起来像是可能导致线程不必要地竞争的东西.
简单地使用类对象作为单例实例,并通过类方法公开功能,即
@interface MySingleton : NSObject {
}
+ (void)doSomething;
@end
@implementation MySingleton
+ (void)initialize {
//do some setup if necessary
}
+ (void)doSomething {
//do something
}
@end
Run Code Online (Sandbox Code Playgroud)
通过这种方式,我们避免每次想要引用单例对象时都进行锁定+检查,我们也可以省去将其存储在本地或方法ivar中.
此方法还允许运行时保证在任何给定时间系统中只存在一个实例(Class对象).
编辑
这里除了线程之外还有更多,使用传统的单例,您通常会编写如下代码:
MySingleton *instance = [MySingleton getSharedInstance];
NSObject *someResult = [instance getResult];
//or
if (instance.someProperty) {
//do something
}
Run Code Online (Sandbox Code Playgroud)
但是,如果你的单例是一个类实例,你基本上就不需要一直调用getSharedInstance.考虑以下代码:
NSObject *someResult = [MySingleton getResult];
//or
if ([MySingleton someProperty]) {
//do something
}
Run Code Online (Sandbox Code Playgroud)
我听说你必须将数据存储在文件本地静态变量或全局变量(yuck)中.但它确实与传统的单例不同,除了你丢失了Objective-C 2.0属性(而是必须使用传统的访问器方法).
这对我来说是一个关键的权衡,似乎是一场胜利.在一个传统的单例中你最终会覆盖-copyWithZone,+ allocWithZone,-retain,-retainCount,-release和-autorelease,如果你真的想要把事情搞定.
每次想要编写一个简单的Singleton对象时,这似乎都是很多工作(它们恰好非常有用).那么为什么不简单地用它替换它:
@implementation MySingleton
+ (void)initialize {
//do your setup
}
- (id)init {
NSAssert(NO, @"You should read the documentation on singletons.");
}
@end
Run Code Online (Sandbox Code Playgroud)
它在代码方面要轻得多,除非你的消费者真的偷偷摸摸,否则他们不会创建两个实例.
已经到了关键点 我的问题是这样的:
使用Class对象作为单例的实例有什么缺点吗?
看起来你可以在线程安全性,内存效率等方面采取所有相同的步骤,而不必记住覆盖如此多的方法和访问器,或者使用实例检查来丢弃代码.
对于iOS 4.0或更高版本,到目前为止最好的解决方案是使用dispatch_once,如同
+ (id)sharedInstance {
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
sharedInstance = [[MyClass alloc] init];
});
return sharedInstance;
}
Run Code Online (Sandbox Code Playgroud)
您可能还想考虑使用单个dispatch_queue来序列化对类的内部的访问.如果所有公共方法只在同一个dispatch_queue上运行一个块,那么您就不必担心并发问题.
这是我在 Stack Overflow 上的第一篇文章......(所以做好愚蠢的准备)
我认为有一种混合解决方案可能有用。
我想从单例类中设置和获取(全局)值,而无需调用“getSharedInstance”。我希望代码看起来像这样......
frameRate = Singleton.frameRate;
Singleton.frameRate = 42;
Run Code Online (Sandbox Code Playgroud)
为了实现这一点,我们需要存储在单例中的每个变量都有一个 getter 和 setter 类方法。然后,类方法转到实例以将数据存储在 ivar 中。主程序不直接访问该实例。
getter 看起来像这样:
+ (int) frameRate
{
return [[Singleton instance] ivarFrameRate];
}
Run Code Online (Sandbox Code Playgroud)
(丑陋的)实例调用隐藏在类代码中。
通过在这里调用实例方法,类方法在第一次使用时会自动实例化一个对象。一旦实例化单例,实例就会按照惯例存储 ivars。在这里,我使用“ivar”作为前缀,使 ivar 明确。
@property int ivarFrameRate;
Run Code Online (Sandbox Code Playgroud)
和
@synthesize ivarFrameRate;
Run Code Online (Sandbox Code Playgroud)
这会自动创建传统的 getter(和 setter)方法来访问 ivar。
(编辑-这是一个完整的例子)
// Singleton.h
#import <Foundation/Foundation.h>
@interface Singleton : NSObject
{
float ivarFrameRate
}
@property float ivarFrameRate;
- (id) init;
+ (Singleton *) instance;
+ (float) frameRate;
+ (void) setFrameRate:(float)fr;
@end
Run Code Online (Sandbox Code Playgroud)
和
// Singleton.m
#import "Singleton.h"
@implementation Singleton
@synthesize ivarFrameRate;
static Singleton* gInstance = NULL;
+ (Singleton*)instance
{
@synchronized(self)
{
if (gInstance == NULL)
gInstance = [[self alloc] init];
}
return(gInstance);
}
- (id)init
{
self = [super init];
return self;
}
+ (float) frameRate
{
return [[Singleton instance] ivarFrameRate];
}
+ (void) setFrameRate:(float)fr;
{
[[Singleton instance] setIvarFrameRate:fr];
}
Run Code Online (Sandbox Code Playgroud)