Reputation:
I'm occasionally getting this crash, which is very hard to reproduce:
0 CoreFoundation 0x39ff73e2 __exceptionPreprocess + 158
1 libobjc.A.dylib 0x3905095e objc_exception_throw + 26
2 CoreFoundation 0x39ffaf2c -[NSObject(NSObject) doesNotRecognizeSelector:] + 180
3 CoreFoundation 0x39ff9648 ___forwarding___ + 388
4 CoreFoundation 0x39f51204 _CF_forwarding_prep_0 + 20
5 Foundation 0x32914bec -[NSDictionary(NSKeyValueCoding) valueForKey:] + 28
6 MyAppName 0x00032112 -[myViewController stopPlayersWithVolume:] (myViewController.m:151)
From this code:
- (void)stopPlayersWithVolume:(double)volume
{
for (NSString *file in players)
{
AVAudioPlayer *player = [players valueForKey:file];
if (player.volume == volume || volume == 0)
[player stop];
}
}
players
is an NSMutableDictionary
property, accessed without self.
because I don't believe it's needed with ARC. The keys are filenames (e.g. "mysound.mp3") and the values are AVAudioPlayer
objects.
Is the stack trace saying that the parameter file
I'm passing to [NSMutableDictionary valueForKey]
is not actually an NSString
, and hence the unrecognised selector? It is always an NSString
in the debugger, as you'd expect as it comes from a fast enumeration through the dictionary, but the crash never occurs in the debugger.
My only thought is that there's a threading issue corrupting the dictionary. The code above is being fired by an NSTimer but that's just a message via the run loop, not a separate thread, so I believe there should be no need to worry about cross-thread access?
Any suggestions appreciated. Sorry to just dump this out but I'm stuck.
Edit:
The players dictionary is allocated in viewDidLoad
thus:
players = [[NSMutableDictionary alloc] init];
And declared as follows:
@property (retain, nonatomic) NSMutableDictionary *players;
And synthesised as follows:
@synthesize players;
Upvotes: 1
Views: 875
Reputation:
The code to allocate the dictionary (and set up the audio stuff) looked like this:
NSError *error = [[NSError alloc] init];
NSArray *names = [fm contentsOfDirectoryAtPath:resourcePath error:&error];
players = [[NSMutableDictionary alloc] init];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&error];
[[AVAudioSession sharedInstance] setActive:YES error:&error];
I must have copied and pasted it from somewhere, because that use of NSError
is wrong, as far as I know, though hardly likely to cause a problem. I changed the code to this:
NSArray *names = [fm contentsOfDirectoryAtPath:resourcePath error:nil];
players = [[NSMutableDictionary alloc] init];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
And the problem goes away, it appears. Can't be 100% sure but I can reproduce the crash within 10 attempts with the former code and never with the latter. No idea why.
Upvotes: 0
Reputation: 57168
It's likely that your players
dictionary or its contents are being deallocated while you're iterating through them. Can you turn on NSZombies and try to reproduce the crash in the debugger? It will give you more information about what object is being deallocated.
Upvotes: 0