2010-07-24 3 views
2

Est-ce que quelqu'un sait pourquoi "construire et analyser" de xCode signalerait cette ligne comme une "fuite de mémoire possible"?"construire et analyser" de Xcode signale des fuites de mémoire impaires pour ce code

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

///// Voici les 4 fichiers en question:

// 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

Je doute que c'est le problème, mais essayez de nommer la méthode 'initWithSound:' au lieu de 'initializeSound:'. Sinon, l'analyseur devrait vous donner des informations plus détaillées sur la raison pour laquelle il pense que c'est un lien si vous cliquez sur les résultats. – jtbandes

Répondre

1

L'analyseur statique est à droite; votre code est une fuite de mémoire possible. Comme l'analyse statique ne peut pas prouver que la méthode dealloc sera toujours appelée (ce qui résoudrait le problème d'arrêt, après), il n'y a aucun moyen pour l'analyseur statique d'être sûr que goodSound sera correctement libéré. L'Objective-C moderne utilise rarement l'accès ivar direct pour accepter les méthodes init et dealloc. Vous devez déclarer un @property (retain) pour votre goodSound, même s'il est privé, et l'utiliser ailleurs dans votre classe, y compris dans la méthode viewDidLoad. L'analyseur statique devrait alors reconnaître correctement ce modèle et ne pas marquer la ligne comme un avertissement.

Sur un côté de note au cas où vous êtes intéressé-votre -[SoundClass initializeSound:] devrait être nommé quelque chose comme -[SoundClass initWithSoundFileName:] à la convention match, et devrait être écrit avec un garde pour tester un retour nil de [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;    
} 

Il est toujours préférable d'ajouter cette protection, en particulier parce que vous appelez du code C qui pourrait ne pas gérer nil/NULL aussi bien que Objective-C.

+0

J'ai fait plusieurs des grandes suggestions ici ... mais le problème a disparu dès que j'ai fait 1 petite modification: Renommez la méthode en initWithSoundFileName. Je pensais que c'était juste une convention de nommage SUGGÉRÉE. Mais il semble que l'analyseur d'Apple affiche/cache des problèmes ... basés sur le * NAME * lui-même. N'est-ce pas dangereux?Si j'avais utilisé ce nom depuis le début ... je n'aurais jamais vu de problèmes ... même s'il y a 2-3 problèmes potentiels. – Annette

+0

@Annette - L'analyseur statique utilise des heuristiques pour l'aider à comprendre votre code, en particulier lorsqu'il s'agit de retenir les comptes renvoyés par les méthodes. Il suit les conventions de nommage Cocoa standard (que vous devriez aussi, comme une aide à la gestion de la mémoire plus tard), donc si vous ne renvoyez pas le nombre de retenue approprié à partir d'une méthode commençant par -init, -copy, etc. versa) il vous en informera. Ce n'est pas cacher des erreurs, c'est simplement signaler les problèmes potentiels lorsque vous ne suivez pas la convention dans votre codage. –

+0

Mais initializeSound et initWithSoundFile commencent tous deux par "init". Quoi qu'il en soit, merci à tous pour toutes ces informations. – Annette

3

Il s'agit d'une fuite de mémoire possible. viewDidLoad peut être appelé autant de fois que la vue est déchargée, auquel cas vous perdrez de la mémoire à chaque fois. Pour se protéger, vous pouvez soit libérer la mémoire dans viewDidUnload et définir l'ivar à zéro, ou vous pouvez simplement initialiser le son en viewDidLoad seulement si le ivar est réellement nul.

Alors:

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

Et/ou:

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

en relation: http://stackoverflow.com/questions/2365440/iphone-super-viewdidunload-calling-order – cregox

Questions connexes