好日子,朋友。Objective-C:静态字段和实现单例模式
有关对象 - 从新手:)
我想实现的OBJ-C单例设计模式再一次愚蠢的问题:
@interface SampleSingleton : NSObject {
@private
static SampleSingleton* instance;
}
+(SampleSingleton*) getInstance;
编译器返回错误:“预期说明符限定符在'静态'之前列出。
好日子,朋友。Objective-C:静态字段和实现单例模式
有关对象 - 从新手:)
我想实现的OBJ-C单例设计模式再一次愚蠢的问题:
@interface SampleSingleton : NSObject {
@private
static SampleSingleton* instance;
}
+(SampleSingleton*) getInstance;
编译器返回错误:“预期说明符限定符在'静态'之前列出。
请在下面找到我使用的Objective-C的代码片段,对正确的线程安全的单身实现
头文件:
/*
*
* Singleton interface that match Cocoa recommendation
* @ http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32
* extended with thread-safe pattern
*/
@interface MyCustomManager : NSObject {
}
#pragma mark Singleton Thred-Safe Pattern
+ (MyCustomManager *) sharedInstance;
+ (id)allocWithZone:(NSZone *)zone;
- (id)copyWithZone:(NSZone *)zone;
- (id)retain;
- (NSUInteger)retainCount;
- (void)release;
- (id)autorelease;
#pragma mark -
实现文件:
/*
* My custom manager Class singleton implementation
*/
@implementation MyCustomManager
#pragma mark Initializers
/*
* specific initialize goes here
*/
- (void) specificInitialize
{
// ...
}
/*
* Ensure any owned object is properly released
*/
- (void) dealloc
{
[super dealloc];
}
#pragma mark -
#pragma mark Singleton Thred-Safe Pattern
//- use Volatile to make sure we are not foiled by CPU caches
static void * volatile sharedInstance = nil;
/*
* retrieve sharedInstance based on OSAtomicCompareAndSwapPtrBarrier that
* acts as both a write barrier for the setting thread and a read barrier from the testing thread
* more info @ http://stackoverflow.com/questions/145154/what-does-your-objective-c-singleton-look-like/2449664#2449664
* and http://stackoverflow.com/questions/6915/thread-safe-lazy-contruction-of-a-singleton-in-c/6943#6943
*/
+ (MyCustomManager *) sharedInstance {
//- check sharedInstance existenz
while (!sharedInstance) {
//- create a temporary instance of the singleton
id temp = [super allocWithZone:NSDefaultMallocZone()];
//- The OSAtomicCompareAndSwapPtrBarrier function provided on Mac OS X
//- checks whether sharedInstance is NULL and only actually sets it to temp to it if it is.
//- This uses hardware support to really, literally only perform the swap once and tell whether it happened.
if(OSAtomicCompareAndSwapPtrBarrier(0x0, (void *)temp, &sharedInstance)) {
//- compute singleton initialize
MyCustomManager *singleton = (MyCustomManager *) sharedInstance;
[singleton specificInitialize];
}
else {
//- if the swap didn't take place, delete the temporary instance
[temp release];
temp = nil;
}
}
//- return computed sharedInstance
return sharedInstance;
}
/*
* method to ensure that another instance is not allocated if someone tries to allocate
* and initialize an instance of your class directly instead of using the class factory method.
* Instead, it just returns the shared object.
*/
+ (id)allocWithZone:(NSZone *)zone
{
return [[self sharedInstance] retain];
}
/*
* Implements the base protocol methods to do the appropriate things to ensure singleton status.
* Applies to memory-managed code, not to garbage-collected code
*/
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
/*
* Implements the base protocol methods to do the appropriate things to ensure singleton status.
* Applies to memory-managed code, not to garbage-collected code
*/
- (id)retain
{
return self;
}
/*
* Implements the base protocol methods to do the appropriate things to ensure singleton status.
* Applies to memory-managed code, not to garbage-collected code
*/
- (NSUInteger)retainCount
{
return NSUIntegerMax; //denotes an object that cannot be released
}
/*
* Implements the base protocol methods to do the appropriate things to ensure singleton status.
* Applies to memory-managed code, not to garbage-collected code
*/
- (void)release
{
//do nothing
}
/*
* Implements the base protocol methods to do the appropriate things to ensure singleton status.
* Applies to memory-managed code, not to garbage-collected code
*/
- (id)autorelease
{
return self;
}
#pragma mark -
只是为了帮助你在Objective-C中开始并且不会迷失在你的项目结构中,你可以考虑让项目结构与你的文件系统相匹配,以便你的项目变得更大你不会迷路。
也请考虑使用适当的类命名约定,并坚持下去。
我一个为您提供矿山为样本:
符合单例模式是使用管理后缀(例如MyCustomManager)命名任何类。
任何静态类都使用助手后缀(例如MyCustomHelper)命名。
任何专门用于控制特定进程的类都使用Controller后缀(例如MyParticularTaskConstroller)来命名。
从另一个控制需要继承任何UI控件提供控制后缀(例如MyCustomDetailCell自定义UITableViewCell继承)
希望这有助于。
静态SampleSingleton* instance;
行不能进入@interface
部分。大多数人把它放在上面。
Objective-c并不适用于单例模式以及其他一些语言。然而在this question中有很多不同的实现。有些人认为辛格尔顿根本不是一个很好的模式,我试图让自己放弃使用它 - 但这是我的选择。
您不能在类接口声明中使用静态。单身人士应在.m
文件中声明为静态独立变量。我通常这样做(如果我觉得我不能避免一个单):
@interface SampleSingleton : NSObject
{
@private
}
+(SampleSingleton*) theSingleton;
@end
// .m file
@implementation SampleSingleton
+(SampleSingleton*) theSingleton
{
static SampleSingleton* theSingleton = nil;
if (theSingleton == nil)
{
theSingleton = [[SampleSingleton alloc] init];
}
return theSingleton;
}
请看看我的问题here和尼克DeMoore精彩的答案(有很多的意见和代码修复)。拥有一个可以在IB中连接的单例(无论你在XCode 4中调用它)是非常有用的。
很酷的事情是,你可以使用同一个Singleton,并将它的一些插座连接到一个NIB,并将它的一些插座连接到另一个插座......因为它实际上是一个单例,整个事件中只能有一个实例运行时系统。工作得非常好。
注意:每次你使用辛格尔顿的人会说这是一个坏主意。
我不认为单身人士是一个坏主意,我只是认为编写大量代码来强制执行它们并不是必要的,在Cocoa中查看你有[NSApplication sharedApplication],[NSNotificationCenter defaultCenter], [NSFileManager的defaultManager]这些都基本上是单身,他们不会尝试任何复杂的init方法。 –
@Nathan Day,这是个好主意,但我的问题是想要将IBOutlets连接到Singelton对象。这充当了中央查询,本质上...我已经被告知(反复)我应该使用依赖注入等,但是我喜欢让方法签名免于重复出现的参数。无论如何,这已经在这里的评论广泛覆盖:http://programmers.stackexchange.com/questions/86202/what-bad-practice-do-you-do-and-why/86211#86211 –
这是怎么了,我通常实现一个单身方法
+(SampleSingleton *)sampleSingleton
{
static SampleSingleton * theSampleSingleton = nil;
if(theSampleSingleton == nil)
theSampleSingleton = [[SampleSingleton alloc] init];
return theSampleSingleton;
}
,使这个线程安全的,你会做
+(SampleSingleton *)sampleSingleton
{
static SampleSingleton * theSampleSingleton = nil;
if(theSampleSingleton == nil)
{
@syncronise([SampleSingleton class])
{
if(theSampleSingleton == nil)
theSampleSingleton = [[SampleSingleton alloc] init];
}
}
return theSampleSingleton;
}
也是而是采用了单,你已经在形式的单的UIApplicationDelegate,你可以随时添加一个方法给你委托从你的委托中获取SampleSingleton。
另一个要考虑的问题是单身人士需要强制执行单身人士,UIApplication有一个共享应用程序来执行创建单身人士的功能,但是没有什么能真正阻止您创建新的实例。
我是害怕你的同步版本被破坏。您**必须**删除无零的外部测试。其中一个原因是,优化编译器会将'theSampleSingleton'加载到第一个测试的寄存器中,并将在同步块内使用相同的寄存器副本进行第二次测试。还有其他更微妙的原因,不要使用它。谷歌为“双重检查锁定”。 – JeremyP
我认为同步块会防止这种情况,谢谢,我将不得不诉诸原子功能。 –
会在单例变量中添加volatile来解决问题。 –
这个解决方案是针对OS X的特定平台,因为我无法在iOS上使用它。你会如何在iOS上做同样的事情? – ArtOfWarfare
@ArtOfWarfare:我在iOS 4上使用它没有任何问题,但它可能受到iOS5 ARC(自动引用计数)引入的影响。如果你使用的是ARC,你可以尝试通过看一下http://stackoverflow.com/a/6308556/734181 –
来关闭这个特定的类。这个答案在iOS 6/7中仍然可以安全使用吗? –