"Построить и проанализировать" XCode сообщает о странных утечках памяти для этого кода - PullRequest
2 голосов
/ 25 июля 2010

Кто-нибудь знает, почему xCode "build and analysis" сообщает об этой строке как о "возможной утечке памяти"?

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 

Ответы [ 2 ]

3 голосов
/ 25 июля 2010

Это возможная утечка памяти. viewDidLoad может вызываться любое количество раз, если представление не загружено, и в этом случае вы будете каждый раз пропускать память. Для защиты вы можете освободить память в viewDidUnload и установить для ivar значение nil, или вы можете просто инициализировать звук в viewDidLoad, только если значение ivar на самом деле равно nil.

Итак:

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

И / или:

- (void)viewDidUnload
{
  [goodSound release];
  goodSound = nil;
  [super viewDidUnload];
}
1 голос
/ 25 июля 2010

Статический анализатор прав;Ваш код - возможная утечка памяти.Поскольку статический анализ не может доказать, что метод MemTestViewController dealloc всегда будет вызываться (это, в конечном счете, решит проблему остановки), статический анализатор не может быть уверен, что goodSound будетправильно выпущено.

Современный Objective-C редко использует прямой доступ к ivar в методах init и dealloc.Вы должны объявить @property (retain) для вашего goodSound, даже если он частный, и использовать его в других местах вашего класса, в том числе в методе viewDidLoad.Статический анализатор должен затем правильно распознать этот шаблон, а не помечать линию как предупреждение.

На заметке - на всякий случай - ваш -[SoundClass initializeSound:] должен быть назван как -[SoundClass initWithSoundFileName:] длясоглашение о совпадении, и должно быть написано с защитой для проверки nil возврата от [super init]:

-(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, который можетне обрабатывать nil/NULL так хорошо, как Objective-C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...