使用[stringWithFormat:]创建NSString时触发EXC_BAD_ACCESS错误的技术求助
排查NSString stringWithFormat:触发EXC_BAD_ACCESS的问题
从你的堆栈追踪和代码来看,这个崩溃发生在stringWithFormat:内部的__CFStringAppendFormatCore方法中,最终调用objc_opt_respondsToSelector时出错——这通常意味着你传给stringWithFormat:的某个参数是无效的Objective-C对象指针(比如野指针、已释放的对象,或者根本不是NSString类型的指针)。
结合你的代码[[NSString stringWithFormat:@"%@/%@/%@",UserLibrary,PREFERENCE_PLIST_DIR_NAME,PREFERENCE_PLIST_NAME] stringByExpandingTildeInPath];,我们可以从以下几个方向排查:
1. 检查UserLibrary的有效性
UserLibrary是普通的NSString*类型,最容易出现的问题是:
- 它是一个野指针:比如指向了已经被释放的内存(ARC下可能是弱引用对象被销毁,MRC下可能是过度释放)
- 它根本不是有效的NSString对象:比如被错误赋值为
nil之外的无效地址
排查&解决方法:
- 在
GetPlistPath方法开头加调试日志,直接打印UserLibrary的地址和值:
如果这行日志就崩溃,说明NSString* GetPlistPath(){ NSLog(@"UserLibrary addr: %p, value: %@", UserLibrary, UserLibrary); return [[NSString stringWithFormat:@"%@/%@/%@",UserLibrary,PREFERENCE_PLIST_DIR_NAME,PREFERENCE_PLIST_NAME] stringByExpandingTildeInPath]; }UserLibrary肯定有问题。 - 确保
UserLibrary的来源可靠:如果是获取用户Library目录,建议直接用系统API生成,避免手动持有指针的内存问题:NSString *UserLibrary = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject]; - ARC环境下检查
UserLibrary的引用类型:如果是__weak修饰的变量,改成__strong,确保对象不会被提前释放;MRC环境下要确保使用前调用过retain,或者它是全局/静态变量。
2. 检查常量宏的定义是否正确
PREFERENCE_PLIST_DIR_NAME和PREFERENCE_PLIST_NAME是NSString* const类型,但如果定义错误,也会导致崩溃:
- 错误示例1:用
#define定义成了C字符串(没有加@):
传给#define PREFERENCE_PLIST_DIR_NAME "Preferences" // 这是const char*,不是NSString*%@格式化符时,系统会把它当成Objective-C对象去调用respondsToSelector,直接触发崩溃。 - 错误示例2:常量没有被正确初始化,比如声明了但没赋值:
NSString* const PREFERENCE_PLIST_DIR_NAME; // 未初始化,指向随机地址
排查&解决方法:
- 确保常量的定义是正确的Objective-C字符串:
NSString* const PREFERENCE_PLIST_DIR_NAME = @"Preferences"; NSString* const PREFERENCE_PLIST_NAME = @"AppSettings.plist"; - 如果用
#define,要加上@,并且确保类型匹配:#define PREFERENCE_PLIST_DIR_NAME @"Preferences"
3. 开启僵尸对象调试(进阶技巧)
在Xcode中开启Zombie Objects诊断,可以更精准地定位是哪个对象被过度释放:
- 打开项目的Scheme(点击Xcode顶部的项目名→Edit Scheme)
- 切换到
Run→Diagnostics选项卡 - 勾选
Zombie Objects - 重新运行程序,崩溃时会给出明确的提示,告诉你哪个已释放的对象被再次访问。
内容的提问来源于stack exchange,提问作者Monika Nainwal
相关产品推荐
相关产品推荐

