Xcode14+中NSXPCInterface setClasses引发懒命名类崩溃求助
问题描述
升级至Xcode 14后,调用NSXPCInterface的setClasses方法时触发SIGABRT崩溃,报错信息为:
Lazily named class 0x600000dc6520 wasn’t named by lazy name handler
该代码在Xcode 13最新版本中可正常编译运行。项目通过MyAppSharedObjects在XPC服务与主应用间传递复杂对象,核心代码如下:
主应用侧核心代码:
import MyAppScriptSandbox import MyAppSharedObjects import Foundation class ScriptExecutor { init?() { let incomingClasses = NSSet(array: [ NSArray.self, NSString.self, NSValue.self, NSNumber.self, NSData.self, NSDate.self, NSNull.self, NSURL.self, NSUUID.self, NSError.self, NSDictionary.self, ScriptSandboxReply.self, AppleScriptError.self, AppleScriptErrorType.self ]) as Set let remoteInterface = NSXPCInterface(with: MyAppScriptSandboxProtocol.self) remoteInterface.setClasses( // **** CRASH HAPPENS HERE **** incomingClasses, for: #selector(MyAppScriptSandboxProtocol.execute(script:withReply:)), argumentIndex: 0, ofReply: true ) } }
XPC协议定义:
import Foundation import MyAppSharedObjects @objc public protocol MyAppScriptSandboxProtocol { func execute( script: String, withReply reply: @escaping (ScriptSandboxReply) -> Void ) func terminate() }
自定义XPC传递类:
@objc(ScriptSandboxReply) public class ScriptSandboxReply: NSObject, NSSecureCoding { public static let supportsSecureCoding = true public func encode(with coder: NSCoder) { // 业务编码逻辑 } required public init?(coder: NSCoder) { // 业务解码逻辑 } }
经排查,崩溃根源在于以下标记@objc的枚举类型:
@objc(AppleScriptErrorType) public enum AppleScriptErrorType: Int { case error case noResult case errorNorResult static let key = "AppleScriptErrorType" }
解决方案
问题本质是Swift的@objc枚举并非真正的Objective-C类,Xcode 14强化了NSXPCInterface对类类型的校验,导致之前的兼容写法失效。具体解决步骤如下:
移除枚举类的注册
从incomingClasses集合中删除AppleScriptErrorType.self,因为枚举不属于NSObject子类,无法被XPC的类注册机制正确处理。修改后的代码:let incomingClasses = NSSet(array: [ NSArray.self, NSString.self, NSValue.self, NSNumber.self, NSData.self, NSDate.self, NSNull.self, NSURL.self, NSUUID.self, NSError.self, NSDictionary.self, ScriptSandboxReply.self, AppleScriptError.self // 移除AppleScriptErrorType.self ]) as Set正确处理枚举的编解码
确保包含该枚举的AppleScriptError类(需实现NSSecureCoding)在编码/解码时,通过枚举的rawValue间接传递:- 编码时:将枚举的
rawValue(Int类型)写入NSCoder - 解码时:从
NSCoder读取Int值,转换回对应枚举类型
- 编码时:将枚举的
依赖自动桥接传递枚举
Swift的Int类型会自动桥接为NSNumber,而NSNumber已在你的incomingClasses集合中,因此枚举的rawValue可以正常通过XPC传递,无需额外注册枚举类。
补充说明:
- 标记
@objc的Swift枚举仅能被Objective-C识别为数值类型的包装,并非真正的Objective-C类,Xcode 14严格执行了这一类型校验,导致Xcode 13中能兼容的写法触发崩溃。 - 所有需要跨XPC传递的自定义类型,必须是继承自
NSObject并实现NSSecureCoding的类,枚举需通过rawValue间接传递。
内容的提问来源于stack exchange,提问作者Lucas van Dongen
相关产品推荐
相关产品推荐

