我在网上发现了单身人士模式。在我看来,它有许多可以优化的东西。
-In sharedMySingleton
方法,无需调用retain?我不确定...
- 如果没有,为什么allocWithZone
中有保留?
- @synchronized
的用途是什么? NSAssert认为可以多次调用块,所以如果是的话,应该有更多的代码来释放以前的内存,或者在没有NSAsserting的情况下清楚地退出块,如果没有,为什么会出现这个NSAssert?
- sharedMySingleton
和alloc
之间的链似乎很奇怪。我给自己写了类似的东西:
+(MySingleton*)sharedMySingleton
{
@synchronized([MySingleton class])
{
if (_sharedMySingleton == nil) _sharedMySingleton = [[self alloc] init];
return _sharedMySingleton;
}
return nil;
}
+(id)alloc
{
@synchronized([MySingleton class])
{
return [super alloc];
}
return nil;
}
单身人士模式
#import "MySingleton.h"
@implementation MySingleton
// ##########################################################################################################
// ######################################## SINGLETON PART ##################################################
// ##########################################################################################################
static MySingleton* _sharedMySingleton = nil;
// =================================================================================================
+(MySingleton*)sharedMySingleton
// =================================================================================================
{
@synchronized([MySingleton class])
{
if (_sharedMySingleton == nil) [[self alloc] init];
return _sharedMySingleton;
}
return nil;
}
// =================================================================================================
+(id)alloc
// =================================================================================================
{
@synchronized([MySingleton class])
{
NSAssert(_sharedMySingleton == nil, @"Attempted to allocate a second instance of a singleton.");
_sharedMySingleton = [super alloc];
return _sharedMySingleton;
}
return nil;
}
+ (id)allocWithZone:(NSZone *)zone { return [[self sharedMySingleton] retain]; }
- (id)copyWithZone:(NSZone *)zone { return self; }
- (id)retain { return self; }
- (NSUInteger)retainCount { return NSUIntegerMax; /* denotes an object that cannot be released */}
- (oneway void)release { /* do nothing */ }
- (id)autorelease { return self; }
// ##########################################################################################################
// ##########################################################################################################
// ##########################################################################################################
// =================================================================================================
-(id)init
// =================================================================================================
{
if (!(self = [super init])) return nil;
return self;
}
// =================================================================================================
-(void) dealloc
// =================================================================================================
{
[super dealloc];
}
// =================================================================================================
-(void)test
// =================================================================================================
{
NSLog(@"Hello World!");
}
@end
答案 0 :(得分:17)
你根本不应该使用这种模式(这是一个非常特殊的Singleton案例,你几乎不需要它,即使在这种情况下你通常也不应该使用它。)
在What should my Objective-C singleton look like?讨论了很多好的模式,但是自GCD发布以来,大多数模式已经过时了。在现代版本的Mac和iOS中,您应该使用以下模式,由Colin Barrett在链接问题中给出:
+ (MyFoo *)sharedFoo
{
static dispatch_once_t once;
static MyFoo *sharedFoo;
dispatch_once(&once, ^{ sharedFoo = [[self alloc] init]; });
return sharedFoo;
}
我只是在这里复制而不是将问题标记为重复,因为旧问题评分最高的答案已过时。
答案 1 :(得分:0)
无需致电retain
,因为有alloc
。最重要的是调用retain
会导致内存泄漏。
allocWithZone
上有保留因为它是单例,所以我们不想创建该类的两个不同实例。而是分配一个新实例,我们增加了单例实例的保留计数。这是为什么?可能是为了防止有人不知道该类的单例类型。如果他调用allocWithZone
然后释放实例,一切仍然正常,他实际上访问了共享的单例实例。
@synchronized
用于防止两个不同线程的两个调用同时进入if语句。所以代码是线程安全的。
如果创建了两个单例实例,则NSSAssert可能会使应用程序“崩溃”。这是“只是为了确定”的代码,也称为防御性编程。
关于sharedMySingleton
和alloc
之间的链接,我认为这很好。
答案 2 :(得分:0)
在sharedMySingleton方法中,不需要调用retain?
alloc
返回引用计数为1的新实例,因此不需要保留。
如果没有,为什么在allocWithZone中有保留?
根据规则,当您致电allocWithZone
时,您拥有该引用,因此allocWithZone
会大大增加您的引用次数。但是allocWithZone的这个实现正在返回已经由其他人创建并拥有的单例实例(sharedMySingleton
方法)。因此sharedMySingleton
方法使用alloc
创建对象,因此它成为所有者。然后,您通过allocWithZone
获得相同的实例,因此您成为同一实例的第二个所有者。因此,保留计数必须增加,因为现在有两个所有者。这就是allocWithZone
需要保留的原因。
@synchronized有什么用?
@synchronized
允许多个线程同时调用代码。如果你永远不会从多个线程中调用sharedMySingleton
,那么就没有必要,你可以省略它。
NSAssert认为可以多次调用块,所以如果 是的,应该有更多的代码来释放以前的内存,或者 在没有NSAsserting的情况下清楚地退出块,如果不是,为什么是 有这个NSAssert?
由于该类旨在成为单例,因此alloc
只应调用一次。如果多次调用NSAssert()
,alloc
将终止该程序。由于NSAssert()
终止程序,当第二次调用alloc
时,不需要内存管理。