2009-05-06 70 views
2

我在應用程序的幾個地方使用單例模式,並且在分析代碼時從clang得到內存泄漏錯誤。Objective-C Singletons和LLVM/clang泄漏警告

static MyClass *_sharedMyClass; 
+ (MyClass *)sharedMyClass { 
    @synchronized(self) { 
    if (_sharedMyClass == nil) 
     [[self alloc] init]; 
    } 
    return _sharedMyClass; 
} 

// clang error: Object allocated on line 5 is no longer referenced after this point and has a retain count of +1 (object leaked) 

我使用這些設置爲scan-build

scan-build -v -v -v -V -k xcodebuild

我相當肯定的是,在單代碼就好了 - 畢竟,這是在這裏提到的相同的代碼堆棧溢出以及蘋果的文檔 - 但我想獲得內存泄漏警告整理出來,所以我的掃描構建返回成功。

回答

6

我可能是非常密集的,但肯定你的5號線

[[self alloc] init]; 

分配包含類類型的對象,並及時拋出它扔掉?你不想要

_sharedMyClass = [[self alloc] init]; 

+0

其實`-init`方法設置靜態_sharedMyClass變量,所以這很好。請參閱:http://stackoverflow.com/questions/145154/what-does-your-objective-c-singleton-look-like/145221#145221 – pix0r 2009-05-06 16:24:08

+2

然後,我會猜測CLANG不夠聰明,推斷[ self alloc] return實際上是設置自身參數,它將由init方法保存。因此它認爲它只是丟失了(就像我做的那樣,沒有更多的上下文)。 – 2009-05-06 16:26:39

+0

大聲笑,你是對的。謝謝。 – pix0r 2009-05-06 18:10:30

0

您還可能有這個在那裏太...

+ (id)allocWithZone:(NSZone *)zone { 
    @synchronized(self) { 
     if (sharedInstance == nil) { 
      sharedInstance = [super allocWithZone:zone]; 
      return sharedInstance; // assignment and return on first allocation 
     } 
    } 
    return nil; // on subsequent allocation attempts return nil 
} 

你不將它存儲在初始化的原因是因爲你在頁頭調用的方法將其存儲。這是蘋果在他們的例子中的模式。如果您將值保存在init中,則一切正常,並且警告消失。我會單獨離開allocWithZone實現。

4

您可能感興趣的一個簡單,一個方法,GCD基於單執行(因此只10.6+)張貼在Mike Ash's site

+ (id)sharedFoo 
{ 
    static dispatch_once_t pred; 
    static Foo *foo = nil; 

    dispatch_once(&pred, ^{ foo = [[self alloc] init]; }); 
    return foo; 
} 
5

蘋果已經因爲更新了他們的recommended singleton code通過靜態分析:

+ (MyGizmoClass*)sharedManager 
{ 
    if (sharedGizmoManager == nil) { 
     sharedGizmoManager = [[super allocWithZone:NULL] init]; 
    } 
    return sharedGizmoManager; 
} 

+ (id)allocWithZone:(NSZone *)zone 
{ 
    return [[self sharedManager] retain]; 
} 

現在+sharedManager調用super的-allocWithZone:並且指定-init的回報,單身的-allocWithZone:只返回一個保留sharedInsta NCE。

編輯:

爲何+ allocWithZone的保留:?

+ allocWithZone:被覆蓋,因爲使用MyGizmoClass的人可以通過調用[[MyGizmoClass alloc] init]而不是[MyGizmoClass sharedManager]來繞過單例。它被保留,因爲+ alloc預計總是返回一個保留數爲+1的對象。

對+ alloc的每次調用都應該使用-release或-autorelease進行平衡,因此如果不在+ allocWithZone:中保留,共享實例可能會從其他用戶下取消分配。

1

您在類方法中引用self!大不 - 不!其次,你打電話[[self alloc] init],只是扔掉實例。您應該在類方法中分配單例引用,而不是像我猜你正在做的那樣在init中。接下來,_sharedMyClass將不會被初始化爲零。您應該明確將其初始化爲nil

static MyClass *_sharedMyClass = nil; 

+ (MyClass *)sharedMyClass { 
    @synchronized(self) { 
    if (_sharedMyClass == nil) 
     _sharedMyClass = [[MyClass alloc] init]; 
    } 
    return _sharedMyClass; 
}