iOS 26 模拟器启动卡死:Method Swizzling 在系统回调时触发 nil 崩溃

一、现象

在 Xcode 26.4 + iOS 26.4 模拟器上运行项目,app 卡在 Launching 界面,始终无法进入主界面。控制台有大量 objc 类重复实现的警告(AuthKitUI / AuthKit 框架重复),但这些是系统 bug,与本次崩溃无关。

使用 LLDB 暂停进程,thread list 看到主线程异常:

arduino 复制代码
thread #1: tid = 0xb124db, 0x0000000118fc9c10 CoreFoundation`-[__NSArrayM insertObject:atIndex:] + 251, queue = 'com.apple.main-thread'

二、定位过程

在 LLDB 中执行 thread select 1 + bt,得到完整调用栈:

less 复制代码
frame #0: CoreFoundation`-[__NSArrayM insertObject:atIndex:] + 251
frame #1: FNCategory`-[NSMutableArray safe_insertObject:atIndex:] at NSMutableArray+FN.m:68
frame #2: FNCategory`-[NSMutableArray safe_addObject:] at NSMutableArray+FN.m:51
frame #3: CoreFoundation`-[NSEnumerator allObjects] + 189
frame #4: AXCoreUtilities`-[AXBinaryMonitor _frameworkNameForImage:]
frame #5: AXCoreUtilities`-[AXBinaryMonitor _handleLoadedImagePath:]
frame #6: AXCoreUtilities`___axmonitor_dyld_image_callback_block_invoke

关键结论 :系统无障碍框架 AXCoreUtilities 在动态加载镜像(dyld image load)时,触发了一个回调,该回调内部调用了 NSEnumerator allObjects,而这个 allObjects 底层最终调用了 NSMutableArray addObject:

由于项目通过 Method Swizzling 将系统的 addObject: 替换成了自定义的 safe_addObject:,这个系统内部调用被"劫持"进了我们的代码。

safe_addObject: 内部调用了 safe_insertObject:atIndex:,这里对 NSMutableArray 插入对象时发生了崩溃。

三、根本原因

这是一个经典的 Method Swizzling 副作用问题 ,iOS 26 改变了 AXCoreUtilities 的内部实现,触发了长期潜伏的 bug。

完整调用链如下:

  1. AXCoreUtilities(系统无障碍框架)在 dyld 加载镜像时触发内部回调
  2. 回调内部操作了一个系统私有数组对象 ,调用了 insertObject:atIndex:
  3. 由于 Method Swizzling,insertObject:atIndex: 已被替换成 safe_insertObject:atIndex:,系统内部调用被"劫持"进了我们的代码
  4. safe_insertObject:atIndex: 内部再调用 [self safe_insertObject:anObject atIndex:index](即原始方法),但此时 self 是系统内部的私有数组类型 ,不是普通的 __NSArrayM,导致无限递归或调用到了错误的 IMP,最终崩溃

问题的本质是:Swizzling 作用在父类(NSMutableArray)上,但系统传入的是私有子类对象,Swizzling 后的方法实现与私有类的内存布局不兼容 ,在 iOS 26 收紧了 AXCoreUtilities 的调用时序之后,这个潜在冲突被激活。

正规的修复思路是在 SwizzlingMethod 里加类型保护,确保只 swizzle __NSArrayM 本身而不影响其私有子类。但由于 FNCategory 是 Pod,还有 AFNetworking、DoraemonKit 等我们无法直接修改源码的三方库存在同样问题,所以统一在 Podfile post_install 里做全局兼容处理。

四、踩过的坑

坑 1:以为是 objc 类重复警告导致的

启动时控制台打印了大量 Class AKAlertImageURLProvider is implemented in both AuthKitUI and AuthKit 的警告,误以为是这些重复类导致崩溃。实际上这是 iOS 26.4 模拟器运行时自身的打包问题,与启动卡死无关。

坑 2:只修复了 FNCategory,没有扩大范围

最初只在 FNCategory 的 NSMutableArray+FN.m 里加了 nil 保护,但 AFNetworking 和 DoraemonKit 也有同样模式的 Swizzling,同样存在风险。

五、修复方案

思路

不针对单个文件做字符串替换,而是在 Podfile 的 post_install 阶段,全局扫描所有 Pod 源文件 ,找到所有 method_exchangeImplementations( 调用,在其前面统一注入 nil 保护。

实现(Podfile post_install)

ruby 复制代码
post_install do |installer|
  # ... 其他 post_install 逻辑 ...

  # 全局修复:为所有 Pod 的 method_exchangeImplementations 调用注入 nil 保护
  # 防止 iOS 26 系统框架在 dyld 镜像加载回调中触发 Swizzled 方法时崩溃
  fixed_count = 0
  Dir.glob('Pods/**/*.{m,mm}').each do |file|
    content = File.read(file)
    next unless content.include?('method_exchangeImplementations(')

    new_content = content.gsub(
      /^(\s*)(method_exchangeImplementations\((\w+)\s*,\s*(\w+)\s*\)\s*;)/
    ) do
      indent = $1
      full_call = $2
      arg1 = $3
      arg2 = $4
      "#{indent}if (#{arg1} && #{arg2}) #{full_call}"
    end

    if new_content != content
      File.chmod(0644, file)
      File.write(file, new_content)
      puts "✅ 已修复 #{file} 的 method_exchangeImplementations nil 保护"
      fixed_count += 1
    end
  end
  puts "共修复 #{fixed_count} 处 method_exchangeImplementations nil 保护" if fixed_count > 0
end

修复效果

执行 pod install 后的输出:

objectivec 复制代码
✅ 已修复 Pods/AFNetworking/AFNetworking/AFNetworking/AFURLSessionManager.m 的 method_exchangeImplementations nil 保护
✅ 已修复 Pods/DoraemonKit/iOS/DoraemonKit/Src/Core/Category/NSObject+Doraemon.m 的 method_exchangeImplementations nil 保护
✅ 已修复 Pods/DoraemonKit/iOS/DoraemonKit/Src/Core/Plugin/Performance/StartTime/DoraemonStartTimeViewController.m 的 method_exchangeImplementations nil 保护
✅ 已修复 Pods/FNCategory/FNCategory/Classes/NSMutableArray+FN.m 的 method_exchangeImplementations nil 保护
✅ 已修复 Pods/FNCategory/FNCategory/Classes/NSObject+FNSwizzle.m 的 method_exchangeImplementations nil 保护
✅ 已修复 Pods/FNCategory/FNCategory/Classes/UIViewController+FNFullScreen.m 的 method_exchangeImplementations nil 保护
Integrating client project
Pod installation complete! There are 32 dependencies from the Podfile and 35 total pods installed.

共修复 6 处,涉及 AFNetworking、DoraemonKit、FNCategory 三个 Pod。

六、总结

项目 说明
问题类型 Method Swizzling 缺少 nil 保护,被系统内部回调触发
触发条件 iOS 26 改变了 dyld 镜像加载回调时序,在类注册完成前触发 Swizzle
崩溃位置 NSMutableArray insertObject:atIndex:safe_insertObject:atIndex:
修复方式 Podfile post_install 全局注入 if (A && B) nil 保护
优点 一次修复,覆盖所有 Pod,无需逐个修改,pod update 后自动重新修复
注意 这是 Swizzling 的通用最佳实践,不局限于 iOS 26,建议所有项目都加上
相关推荐
YJlio21 小时前
10.2.8 以其他账户运行服务(Running services in alternate accounts):为什么“把服务切到某个用户账号下运行”,本质上是在改变服务的整个安全上下文?
python·安全·ios·机器人·django·iphone·7-zip
pop_xiaoli1 天前
【iOS】KVC与KVO
笔记·macos·ios·objective-c·cocoa
90后的晨仔1 天前
《swiftUI进阶 第10章:现代状态管理(iOS 17+)》
ios
sakiko_1 天前
UIKit学习笔记4-使用UITableView制作滚动视图
笔记·学习·ios·swift·uikit
小锋学长生活大爆炸2 天前
【开源软件】这次iPhone也是用上Claw了 | PhoneClaw
ios·开源软件·iphone·claw
SameX2 天前
独立开发一个把走过的路变成 km² 的 App,聊聊 25m 网格和后台 GPS 的坑
ios
XD7429716362 天前
科技早报晚报|2026年4月30日:Agent 安全壳、浏览器 iOS 测试台与可穿戴数据 API,今天更值得看的 3 个技术机会
科技·ios·开源项目·科技新闻·开发者工具
北京自在科技2 天前
Find Hub App 小更新
android·ios·安卓·findmy·airtag
2501_915921432 天前
HTTPS前端劫持 新一代流量劫持解决方案
前端·网络协议·ios·小程序·https·uni-app·iphone
911hzh2 天前
Flutter WebRTC iOS 原理解析:从 getUserMedia 到 Texture,讲清视频采集、纹理渲染与远端通话链路
flutter·ios·webrtc