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
相关产品推荐
相关产品推荐

