2010-07-24 52 views
2

有誰知道爲什麼xCode的「構建和分析」會報告此行爲「可能的內存泄漏」?Xcode的「構建和分析」報告此代碼奇怪的內存泄漏

goodSound = [[SoundClass alloc] initializeSound:@「Good.wav」];

/////這裏有4個文件中的問題:

// Sounds.h 

#import <Foundation/Foundation.h> 
#import <AudioToolbox/AudioToolbox.h> 

@interface SoundClass : NSObject 
{ 
    SystemSoundID soundHandle; 
} 

-(id) initializeSound:(NSString *)soundFileName; 
-(void) play;  

@end 

/////////////

// Sounds.m 

#import "Sounds.h" 

@implementation SoundClass 

-(id) initializeSound:(NSString *)soundFileName 
{ 
    self = [super init]; 

    NSString *const resourceDir = [[NSBundle mainBundle] resourcePath]; 
    NSString *const fullPath = [resourceDir stringByAppendingPathComponent:soundFileName]; 
    NSURL *const url   = [NSURL fileURLWithPath:fullPath]; 

    OSStatus errCode = AudioServicesCreateSystemSoundID((CFURLRef) url, &soundHandle); 

    if(errCode == 0) 
     NSLog(@"Loaded sound: %@", soundFileName); 
    else 
     NSLog(@"Failed to load sound: %@", soundFileName); 

    return self;    
} 

////////////////////////////// 

-(void) play  
{ 
    AudioServicesPlaySystemSound(soundHandle); 
} 

///////////////////////////// 

-(void) dealloc 
{ 
    AudioServicesDisposeSystemSoundID(soundHandle); 
    [super dealloc]; 
} 

///////////////////////////// 

@end 

//// //////////

// MemTestViewController.h 

#import <UIKit/UIKit.h> 

@class SoundClass; 

@interface MemTestViewController : UIViewController 
{ 
    SoundClass *goodSound; 
} 

-(IBAction) beepButtonClicked:(id)sender; 

@end 

///////////

// MemTestViewController.m 

#import "MemTestViewController.h" 
#import "Sounds.h" 

@implementation MemTestViewController 

- (void)viewDidLoad 
{ 
    NSLog(@"view did load: alloc'ing mem for sound class"); 

    // "build and analyze" says this is possibly a memory leak: 
    goodSound = [[SoundClass alloc] initializeSound:@"Good.wav"]; 

    [super viewDidLoad]; 
} 


-(IBAction) beepButtonClicked:(id)sender 
{ 
    NSLog(@"beep button clicked"); 

    [goodSound play]; 
} 


- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
} 


- (void)dealloc 
{ 
    [goodSound release]; 
    [super dealloc]; 
} 

@end 
+1

我懷疑這是問題,但嘗試命名方法'initWithSound:',而不是'initializeSound:'。 否則,如果您點擊結果,分析儀應該爲您提供更多關於爲什麼認爲它是鏈接的詳細信息。 – jtbandes 2010-07-24 20:22:02

回答

1

靜態分析器是正確的;你的代碼是可能的內存泄漏。因爲靜態分析不能證明MemTestViewController的方法總是被調用(這樣做會解決暫停問題,畢竟),靜態分析器無法確定goodSound將被正確釋放。

現代Objective-C很少使用直接ivar訪問接受initdealloc方法。你應該爲你的goodSound申報@property (retain),即使它是私密的,並在你的課程中的其他地方使用,包括viewDidLoad方法。然後,靜態分析儀應能正確識別此模式,而不會將該線標記爲警告。

在一個側面說明,以防萬一你有興趣,你-[SoundClass initializeSound:]名稱應該像-[SoundClass initWithSoundFileName:]匹配約定,並應保護被寫入測試從[super init]一個nil回報:

-(id)initWithSoundFileName:(NSString*)soundFileName 
{ 
    self = [super init]; 

    if(self != nil) { 
     NSString *const resourceDir = [[NSBundle mainBundle] resourcePath]; 
     NSString *const fullPath = [resourceDir stringByAppendingPathComponent:soundFileName]; 
     NSURL *const url   = [NSURL fileURLWithPath:fullPath]; 

     OSStatus errCode = AudioServicesCreateSystemSoundID((CFURLRef) url, &soundHandle); 

     if(errCode == 0) 
     NSLog(@"Loaded sound: %@", soundFileName); 
     else 
     NSLog(@"Failed to load sound: %@", soundFileName); 
    } 

    return self;    
} 

總是最好添加這個警衛,尤其是因爲你正在調用C代碼,可能無法像Objective-C一樣處理nil/NULL

+0

我在這裏提出了幾個很棒的建議......但是,只要我做了一個小改動,問題就消失了:將該方法重命名爲initWithSoundFileName。我認爲這只是一個SUGGESTED命名約定。但它似乎像蘋果的分析儀顯示/隱藏問題......基於* NAME *本身。這不危險嗎?如果我從一開始就使用這個名字......我從來沒有見過任何問題...即使我們有2-3個潛在的問題。 – Annette 2010-07-25 03:52:39

+0

@Annette - 靜態分析器使用一些啓發式方法來幫助理解代碼,特別是當保留從方法返回的計數時。它遵循標準的Cocoa命名約定(你也應該這樣做,以便稍後幫助管理內存),所以如果你沒有從以-init,-copy等開頭的方法返回適當的保留計數(或者副作用相反)它會告訴你這一點。這不是隱藏錯誤,只是指出當你不遵守約定時的潛在問題。 – 2010-07-25 04:04:52

+0

但initializeSound和initWithSoundFile都以「init」開頭。無論如何,感謝所有偉大的信息大家。 – Annette 2010-07-26 00:29:24

3

這是一個可能的內存泄漏。如果視圖被卸載,則可以調用任何次數的viewDidLoad,在這種情況下,每次都會泄漏內存。爲了防範,您可以釋放viewDidUnload中的內存並將伊娃設置爲零,或者只有當伊娃實際爲零時,纔可以簡單地初始化viewDidLoad中的聲音。

所以:

- (void)viewDidLoad 
{ 
    if(!goodSound) 
    goodSound = [[SoundClass alloc] initializeSound:@"Good.wav"]; 
    [super viewDidLoad]; 
} 

和/或:

- (void)viewDidUnload 
{ 
    [goodSound release]; 
    goodSound = nil; 
    [super viewDidUnload]; 
} 
+0

相關:http://stackoverflow.com/questions/2365440/iphone-super-viewdidunload-calling-order – cregox 2011-01-12 12:41:24