Search code examples
xcodememoryautomatic-ref-countinginstruments

ARC memory management issue with system sounds


I’m playing a system sound using...

    NSString *path = [NSString stringWithFormat:@"%@%@",
                      [[NSBundle mainBundle] resourcePath],
                      @"/heartbeat.wav"];

    //declare a system sound id
    SystemSoundID soundID4;

    //Get a URL for the sound file
     NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];

    //Use audio sevices to create the sound
    AudioServicesCreateSystemSoundID((__bridge_retained CFURLRef)filePath, &soundID4);

    //Use audio services to play the sound
    AudioServicesPlaySystemSound(soundID4);

    AudioServicesDisposeSystemSoundID(soundID4);

I’m not sure that this is the problem.. but if it run with “analyze” it comes up as a potential leak. There is clearly some kind of leak going on as the app gets slower and slower as I run it more times in the simulator. I have found examples for how to deal with this without using arc, but nothing with. Any suggestions would be greatly appreciated.


Solution

  • "it comes up as a potential leak". What is "it"?

    Second, you don't analyze a memory leak by observing a program getting slower and slower. In fact, that's not a normal symptom of a memory leak unless you are exhausting physical RAM and causing lots of swapping. You diagnose a leak by actually identifying no-longer-reachable memory using something like the Leaks instrument.

    That said, you don't want __bridge_retained, you just want __bridge. One of the reasons I prefer the CFBridgingRetain() and CFBridgingRelease() functions rather than the __bridge_retained and __bridge_transfer casts is that you are much less likely to make such a mistake. For example, you'd never have written:

    AudioServicesCreateSystemSoundID(CFBridgingRetain(filePath), &soundID4);
    

    First of all, it's obvious that there's no need to retain filePath just to pass it to a function. Second, calling a CFRetain()-style function also makes it clear that you have a responsibility to calling a CFRelease()-style function to balance it.