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

多Target的SPM包加载Nib时出现类型转换失败问题

问题:SPM多Target场景下Nib加载类型转换失败

我创建了一个包含两个Target的SPM包,第二个Target依赖第一个Target,Package的描述代码如下:

let package = Package(
    name: "MyPackage",
    platforms: [.iOS(.v15)],
    products: [
        .library(
            name: "MyPackage",
            targets: ["MyPackage"]),
        .library(
            name: "MyPackage2",
            targets: ["MyPackage2"])
    ],
    dependencies: [
        .package(name: "A", path: "../A"),
        .package(name: "B", path: "../B"),
        .package(name: "C", path: "../C"),
        .package(name: "D", path: "../D"),
        .package(name: "E", path: "../E"),
        .package(name: "F", path: "../F")
    ],
    targets: [
        .target(
            name: "MyPackage",
            dependencies: [
                "A",
                "B",
                "C",
                "D",
                "E",
                "F"
            ],
            resources: [
                .process("Resources")
            ]
        ),
        .testTarget(
            name: "MyPackageTests",
            dependencies: [
                "MyPackage"
            ]
        ),
        .target(
            name: "MyPackage2",
            dependencies: [
                "MyPackage"
            ],
            resources: [
                .process("Resources")
            ]
        )
    ]
)

在第一个Target中加载内部Nib文件时,出现类型转换失败问题。加载Nib的代码如下:

public final class func loadFrom(_ bundle: Bundle) -> Self {
    let nibName = String(describing: self)
    return bundle.loadNibNamed(nibName, owner: nil, options: nil)?.first as! Self
}

注:Nib加载本身并未失败,打印bundle.loadNibNamed(nibName, owner: nil, options: nil)?.first能得到正确结果,但执行as! Self时失败,错误信息为:

Could not cast value of type 'X' (0x1109e0c98) to 'X' (0x103db62e8).

该问题在添加第二个Target后出现,请问原因是什么?


原因与解决方案

核心原因

这个问题的本质是同一个类被重复加载,内存中存在两个独立的类元数据实例。当你同时在Package中暴露MyPackage和MyPackage2两个产品库,且主项目同时引入这两个库时,MyPackage中的代码会被链接两次:一次直接来自MyPackage库,另一次通过MyPackage2的依赖间接引入。这就导致内存中出现两个完全不同的X类定义,Nib加载的实例属于其中一个版本,而代码中要转换的Self是另一个版本,类型转换必然失败。

解决办法

  1. 调整Package产品暴露策略:
    不要将MyPackage作为独立产品对外暴露,只提供MyPackage2作为唯一对外产品,因为MyPackage2已经依赖MyPackage,内部会包含其代码。修改Package的products部分:

    products: [
        .library(
            name: "MyPackage2",
            targets: ["MyPackage2"])
    ],
    
  2. 避免主项目重复引入:
    确保主项目只引入一个产品库——要么只引入MyPackage,要么只引入MyPackage2,不要同时添加两个,从根源上避免重复链接。

  3. 规范资源配置:
    两个Target都配置了.process("Resources"),如果两者的Resources目录存在同名Nib文件,可能会混淆资源加载的归属。建议给每个Target的资源目录设置唯一名称(比如MyPackageResources和MyPackage2Resources),或者只在MyPackage中处理自身资源,MyPackage2仅处理专属资源。

内容的提问来源于stack exchange,提问作者Nimrod Shai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 12:00:58