2012-04-08 98 views
5

我發現網上的單身模式。在我看來,它有很多可以優化的東西。Objective-C - 優化這個單例模式?

-In sharedMySingleton方法,不需要調用保留?我不確定...
- 如果沒有,爲什麼在allocWithZone有保留?
- @synchronized有什麼用。 NSAssert認爲塊可以被多次調用,所以如果是的話,應該有更多的代碼來釋放先前的內存,或者不用NSAsserting就可以清楚地退出塊,如果沒有,爲什麼會出現這個NSAssert?
-和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; 
} 

Singleton模式

#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 

回答

17

你不應該使用在所有這些模式(它是辛格爾頓的一個非常特殊的情況下,你幾乎從來沒有需要,即使在這種情況下,你通常不應該使用它)。

What should my Objective-C singleton look like?討論了很多很好的模式,但其中大多數自GCD發佈以來已過時。在Mac和iOS的現代版本,你應該在鏈接的問題使用下面的模式,由科林·巴雷特給出:

+ (MyFoo *)sharedFoo 
{ 
    static dispatch_once_t once; 
    static MyFoo *sharedFoo; 
    dispatch_once(&once, ^{ sharedFoo = [[self alloc] init]; }); 
    return sharedFoo; 
} 

我只在這裏複製它,而不是標記的問題複製,因爲這個老問題的收視率最高的答案已經過時。

+0

其他方法呢?保留,retaincount,release,copyWithZone,...?你爲什麼在談論「現代」版本?現代你的意思是什麼?想知道爲什麼Apple沒有用這種代碼更新它的單例代碼片段? – Oliver 2012-04-10 08:54:56

+1

現代,我的意思是自推出GCD。你不應該重寫這些方法。顯示覆蓋這些的唯一示例代碼在這裏:https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html正如它注意到的,這是一個* strict *實現單身人士,上面解釋的文字通常是不需要的。我已經打開了一個doc案例來改進這個文檔,因爲它讓很多開發人員感到困惑。 Mike Ash在這方面有一個很好的帖子:http://www.mikeash.com/pyblog/friday-qa-2009-10-02-care-and-feeding-of-singletons.html – 2012-04-10 14:15:10

+0

相當於10.6英寸iOS的條款? – Oliver 2012-04-11 08:52:31

0

因爲有alloc,所以不需要撥打retain。撥打retain會導致內存泄漏。 allocWithZone上有保留,因爲它是一個單例,所以我們不想創建兩個不同的類的實例。而是分配一個新的實例,我們增加了單例實例的保留數。這是爲什麼?可能是爲了防止有人不知道該類的單身類型。如果他調用allocWithZone然後釋放實例,那麼一切仍然正常,他實際上訪問共享的單例實例。

@synchronized用於防止來自兩個不同線程的兩個調用同時輸入到if語句中。所以代碼是線程安全的。

如果創建了兩個單例實例,NSSAssert可能會使應用程序「崩潰」。這是'即將確定'的代碼,也被稱爲防禦性編程。

關於連鎖sharedMySingletonalloc,我認爲這很好。

0

在sharedMySingleton方法中,不需要調用retain?

alloc返回一個引用計數爲1的新實例,因此不需要保留。

如果不是,爲什麼在allocWithZone中有保留?

根據規則,當你調用allocWithZone,你自己的參考,因此allocWithZone多增加您的引用計數。但是這個allocWithZone的實現是返回已經創建並由其他人擁有的單例實例(sharedMySingleton方法)。所以sharedMySingleton方法創建對象alloc,因此它成爲一個所有者。然後您通過allocWithZone獲得相同的實例,因此您成爲同一實例的第二個所有者。所以保留數量必須增加,因爲現在有兩個所有者。這就是爲什麼allocWithZone需要保留。

@synchronized有什麼用?

@synchronized允許代碼被多個線程同時調用。如果您不會從多個線程中調用sharedMySingleton,那麼這不是必需的,您可以省略它。

的NSAssert使認爲該塊可以被稱爲很多次,所以如果 是,應該有一些更多的代碼來釋放以前的記憶,或 退出該塊顯然不只是NSAsserting,如果沒有,爲什麼是 有沒有這個NSAssert?

因爲這個類是單身人士,所以alloc只應該被調用一次。如果alloc被多次調用,NSAssert()終止程序。由於NSAssert()終止程序,所以當第二次調用alloc時,不需要存儲器管理。