EXC_BAD_ACCESS KERN_INVALID_ADDRESS 来自一些用户

EXC_BAD_ACCESS KERN_INVALID_ADDRESS from some users

同时,我无法在我的测试设备/模拟器上重现这个问题,我从一些用户那里收到了一些崩溃报告,但不是全部。 EXC_BAD_ACCESS KERN_INVALID_ADDRESS 在这一行。为什么会这样,我可以采取哪些步骤来解决?崩溃报告来自 iOS 14.4.0 和 14.3.0 的用户以及各种设备(iPhone 6s plus,iPhone 8 Plus,iPhone SE(2nd代), iPhone XS, iPhone 7, iPhone 7s, iPhone 11, iPhone 12, iPhone X)

在PageViewController.m

// Voice Recording - Needed as workaround as there is a bug in AudioKit
NSArray *pathComponents = [NSArray arrayWithObjects:
                           [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
                           defaultVoiceRecording,
                           nil];
NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];

// Setup audio session to play through loud speakers
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error;
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
if(error){
    NSLog(@"AVAudioSession Sing the Note error tuner:%@",error);
}

// Setup audio session to play through loud speakers
if (![MenuViewController areHeadphonesPluggedIn]){ // EXC_BAD_ACCESS KERN_INVALID_ADDRESS here
    
    [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
    if(error)
    {
        NSLog(@"Error: AudioSession cannot use speakers");
    }
}

在MenuViewController.h

+(BOOL)areHeadphonesPluggedIn;

在MenuViewController.m

+(BOOL)areHeadphonesPluggedIn {
    @try{
        NSArray *availableOutputs = [[AVAudioSession sharedInstance] currentRoute].outputs;
        for (AVAudioSessionPortDescription *portDescription in availableOutputs) {
            if ([portDescription.portType isEqualToString:AVAudioSessionPortHeadphones]) {
                return YES;
            }
        }
        return NO;
    }
    @catch(id Exception){
        return NO;
    }
}
+(BOOL)areHeadphonesPluggedIn {
    @try{
        NSArray *availableOutputs = [[AVAudioSession sharedInstance] currentRoute].outputs;
        for (AVAudioSessionPortDescription *portDescription in availableOutputs) {
            if ([portDescription.portType isEqualToString:AVAudioSessionPortHeadphones]) {
                return YES;
            }
        }
        return NO;
    }
    @catch(id Exception){
        return NO;  // Not sure it will work as you exect
    }
   return NO;  // move return here!
}

这个问题归因于堆栈上某处的 'dangling' 指针,在本例中是自动释放数组 pathComponents。需要将其更改为非自动释放数组。

完整解决方案PageViewController.m

   // Change from autorelease to normal non-autorelease
   NSArray *pathComponentsSN = [[NSArray alloc] initWithObjects:     
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],defaultVoiceRecording,nil];
    
    NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponentsSN];
    
    // Setup audio session to play through loud speakers
    AVAudioSession *session = [AVAudioSession sharedInstance];
    NSError *error;
    [session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
    if(error){
        NSLog(@"AVAudioSession Sing the Note error creating session");
    }
    
    // Setup audio session to play through loud speakers
    if (![MenuViewController areHeadphonesPluggedIn]){ // Crash logs from this line
        
        [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
        if(error)
        {
            NSLog(@"Error: AudioSession cannot use speakers");
        }
    }