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

iOS多动态框架场景下Singleton类为何出现多个实例?

多模块下Singleton出现多个实例的原因及解决

问题背景

主项目ModuleDemo依赖ModuleA、ModuleB和ModuleC,项目的Podfile内容如下:

platform :ios, '13.0'
use_frameworks! :linkage => :static

workspace 'Module.xcworkspace'

def downloader
  pod 'Downloader'
end

def treasureBox
  pod 'TreasureBox'
end

abstract_target 'ModuleDemo' do

    target "ModuleDemo" do
        project 'ModuleDemo/ModuleDemo.xcodeproj'
    downloader
    end

    target "ModuleA" do
        project 'ModuleA/ModuleA.xcodeproj'
    downloader
    treasureBox
    end

    target "ModuleB" do
        project 'ModuleB/ModuleB.xcodeproj'
    downloader
    treasureBox
    end

    target "ModuleC" do
        project 'ModuleC/ModuleC.xcodeproj'
    downloader
    treasureBox
    end
end

测试发现每个模块会生成独立的动态framework,Downloader被重复拷贝到每个模块中,运行后内存里出现了多个Downloader的Singleton实例——按常识Singleton在单个进程里应该只有一个实例,这是为什么?

原因分析

  • 虽然Podfile里配置了use_frameworks! :linkage => :static,但每个target(ModuleA/B/C+主项目)都单独引入了Downloader。每个模块是独立的动态framework,编译时会把Downloader的静态代码分别打包进各自的动态framework中。
  • 动态framework在iOS进程里是独立的加载单元,每个都有自己的全局变量空间。而Singleton的核心逻辑是用全局静态变量存储唯一实例,所以每个动态framework里的Downloader都会创建属于自己的全局静态变量,自然就产生了多个实例。
  • 你理解的“单进程内Singleton唯一”是同一个二进制单元(比如主APP或者单个动态framework)内的规则,但多个独立动态framework相当于进程里的多个独立“子环境”,它们的全局变量完全不共享。

解决办法

方案1:统一依赖层级

只在主target(ModuleDemo)中引入Downloader,ModuleA/B/C不再单独引入,而是通过主APP的依赖来使用Downloader。这样Downloader只会被打包进主APP的二进制,所有模块共享同一个实例。

方案2:用inherit! :search_paths统一依赖

修改Podfile,让子target继承主target的依赖搜索路径,避免重复引入:

platform :ios, '13.0'
use_frameworks! :linkage => :static

workspace 'Module.xcworkspace'

def downloader
  pod 'Downloader'
end

def treasureBox
  pod 'TreasureBox'
end

abstract_target 'ModuleDemo' do
    # 让子target继承主target的依赖搜索路径
    inherit! :search_paths

    target "ModuleDemo" do
        project 'ModuleDemo/ModuleDemo.xcodeproj'
        downloader
    end

    target "ModuleA" do
        project 'ModuleA/ModuleA.xcodeproj'
        treasureBox
    end

    target "ModuleB" do
        project 'ModuleB/ModuleB.xcodeproj'
        treasureBox
    end

    target "ModuleC" do
        project 'ModuleC/ModuleC.xcodeproj'
        treasureBox
    end
end

这样ModuleA/B/C会复用主target中的Downloader,不会重复打包,也就不会出现多个Singleton实例了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 04:40:15