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

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对类类型的校验,导致之前的兼容写法失效。具体解决步骤如下:

  1. 移除枚举类的注册
    从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
    
  2. 正确处理枚举的编解码
    确保包含该枚举的AppleScriptError类(需实现NSSecureCoding)在编码/解码时,通过枚举的rawValue间接传递:

    • 编码时:将枚举的rawValue(Int类型)写入NSCoder
    • 解码时:从NSCoder读取Int值,转换回对应枚举类型
  3. 依赖自动桥接传递枚举
    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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 21:15:36