You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Objective-C调用[NSLocale currentLocale]时App在特定设备偶发崩溃

问题描述

使用Objective-C开发iOS应用时,调用[NSLocale currentLocale]获取当前系统区域会触发App崩溃。该问题无法在全量设备复现,仅在某台特定的iPhone 13 Pro真机上触发,其余同型号iPhone 13 Pro真机均无该异常;且应用完全不支持模拟器运行,无法通过模拟器调试定位,需可行的解决方案。

崩溃采集信息

Crashlytics采集的崩溃堆栈如下:

Crashed: com.apple.main-thread
EXC_BAD_ACCESS KERN_PROTECTION_FAILURE 0x000000016bcfffb0
CoreFoundation
_CFLocaleCopyCurrentGuts + 4
SKCountryPicker.m - Line 74
-[SKCountryPicker defaultCountryCode] + 74  
SKCountryPicker.m - Line 81
-[SKCountryPicker getCountryDetailBasedOnSIMAndIOSSettings] + 81
SKCountryPicker.m - Line 94
-[SKCountryPicker getCountryDetailForCountryCode:] + 94  
SKCountryPicker.m - Line 81
-[SKCountryPicker getCountryDetailBasedOnSIMAndIOSSettings] + 81
SKCountryPicker.m - Line 94
-[SKCountryPicker getCountryDetailForCountryCode:] + 94
SKCountryPicker.m - Line 87
-[SKCountryPicker getCountryDetailBasedOnSIMAndIOSSettingsForCountryList:] + 87
SKCountryPicker.m - Line 65
__49-[SKCountryPicker getCountryListSuccess:failure:]_block_invoke_2 + 65
Foundation
__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 4330003460
Foundation
-[NSBlockOperation main] + 4330004024
Foundation
__NSOPERATION_IS_INVOKING_MAIN__ + 4330003460
Foundation
-[NSOperation start] + 4330004024
Foundation
__NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 4330003460
Foundation
__NSOQSchedule_f + 4330004024
libdispatch.dylib
_dispatch_block_async_invoke2 + 4330003460
libdispatch.dylib
_dispatch_client_callout + 4330004024
libdispatch.dylib
_dispatch_main_queue_drain + 4330003460
libdispatch.dylib
_dispatch_main_queue_callback_4CF + 4330004024
CoreFoundation
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 4330003460

崩溃类型为内存访问错误,触发点在CoreFoundation内部的_CFLocaleCopyCurrentGuts函数。

对应崩溃源码

崩溃堆栈对应源码第74、81行实现如下:

-(NSString*)defaultCountryCode {
    NSLocale *currentLocale = [NSLocale currentLocale];
    NSString *countryCode = [currentLocale objectForKey:NSLocaleCountryCode];
    return countryCode;
}

-(SKCountry*)getCountryDetailBasedOnSIMAndIOSSettings {
    SKCountry *selectedCountryData = [self getCountryDetailForCountryCode: [self defaultCountryCode]];
    return selectedCountryData;
}

崩溃截图

解决方案
  • 修复多线程访问风险:[NSLocale currentLocale]在部分iOS系统版本中,跨线程并发调用时可能触发底层缓存访问异常。当前堆栈逻辑由NSOperationQueue调度最终切回主线程执行,可强制将获取Locale的逻辑固定在主线程同步执行,避免跨线程访问问题。
    参考修改代码:
    -(NSString*)defaultCountryCode {
        __block NSString *countryCode = nil;
        if ([NSThread isMainThread]) {
            NSLocale *currentLocale = [NSLocale currentLocale];
            countryCode = [currentLocale objectForKey:NSLocaleCountryCode];
        } else {
            dispatch_sync(dispatch_get_main_queue(), ^{
                NSLocale *currentLocale = [NSLocale currentLocale];
                countryCode = [currentLocale objectForKey:NSLocaleCountryCode];
            });
        }
        // 兜底默认值,可根据产品需求替换
        if (!countryCode) {
            countryCode = @"US";
        }
        return countryCode;
    }
    
  • 排查SKCountryPicker内部递归问题:从堆栈可见getCountryDetailBasedOnSIMAndIOSSettings和getCountryDetailForCountryCode:存在互相递归调用的情况,需检查两个方法的逻辑,补充递归终止条件,避免无限递归导致栈溢出、内存越界访问受保护页。
  • 兼容非官方系统修改场景:单台设备复现的系统API崩溃,大概率是设备开启越狱环境、安装了区域/定位修改类插件,篡改了系统Locale相关的底层数据,导致系统API返回异常对象。可增加@try-@catch异常捕获兜底,同时提供备用的区域获取逻辑,比如通过[[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLocale"]获取区域标识后解析国家码,绕过异常的系统API路径。
  • 真机定位方式:无需模拟器,直接将异常的iPhone 13 Pro连接Xcode,添加EXC_BAD_ACCESS断点和全局异常断点,触发崩溃时可直接查看内存状态、寄存器信息,确认崩溃根因。

内容的提问来源于stack exchange,提问作者Sachin Mishra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 16:57:48