pod使用静态库,提升App启动速度,降低包大小

列表

cocoapods 1.5更新描述

xcode9支持swift静态库,在Cocoapods 1.5.0中支持了导入swift静态库,不需要再指定 use_frameworks! 。需要注意的是当你的一个swift pod模块依赖一个OC pod模块时需要开启Modular Headers,三种方式:
1.在podfile中添加 use_modular_headers! ,这种方式将使得所有的pod模块都能使用@import导入。

platform :ios, '9.0'
use_modular_headers!

target 'staticpod' do
 pod 'SwiftModule', :path => '../SwiftModule'
 pod 'ObjectiveModule', :path => '../ObjectiveModule'

2.在podfile中对应的pod模块后添加 :modular_headers => true ,这种方式将使得对应的pod模块能使用@import导入。

pod 'ObjectiveModule', :path => '../ObjectiveModule', :modular_headers => true

3.在模块的podspec中添加 'DEFINES_MODULE' => 'YES' 到你的 pod_target_xcconfig 中,这种方式将指定你的podspec的模块能使用@import导入。

spec.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }

PS:在cocoapod不使用 use_frameworks! 时,OC模块无法使用@import导入,use_modular_headers! 的意思是OC模块可以使用@import

#import和@import区别

#import :

​ 我相信每个开发者都写过这样的代码 #import <FrameworkFoo/HeaderBar.h> ,用来引用其他的头文件。熟悉C或者C++的童鞋可能会知道,在C和C++里是没有#import的,只有#include(虽然GCC现在为C和C++做了特殊处理使得import可以被编译),用来包含头文件。#include做的事情其实就是简单的复制粘贴,将目标.h文件中的内容一字不落地拷贝到当前文件中,并替换掉这句include,而#import实质上做的事情和#include是一样的,只不过OC为了避免重复引用可能带来的编译错误(这种情况在引用关系复杂的时候很可能发生,比如B和C都引用了A,D又同时引用了B和C,这样A中定义的东西就在D中被定义了两次,重复了),而加入了#import,从而保证每个头文件只会被引用一次。

@import :

​ Modules相当于将框架进行了封装,然后加入在实际编译之时加入了一个用来存放已编译添加过的Modules列表。如果在编译的文件中引用到某个Modules的话,将首先在这个列表内查找,找到的话说明已经被加载过则直接使用已有的,如果没有找到,则把引用的头文件编译后加入到这个表中。这样被引用到的Modules只会被编译一次,但是在开发时又不会被意外使用到,从而同时解决了编译时间和引用泛滥两方面的问题。

测量Pre-mainTime

一个App在执行main函数前包括app delegate的系列方法如applicationWillFinishLaunching时,会做许多系统级别的准备.而在iOS10之前,开发者很难清楚自己App为何启动加载慢.而通过在工程的scheme中添加环境变量 DYLD_PRINT_STATISTICS ,设置Value为 1 ,App启动加载时就会有启动过程的日志输出. 现在(iOS 10之后)Apple对DYLD_PRINT_STATISTICS的日志输出结果进行了简化,使得更容易让开发者理解.

Total pre-main time: 1.5 seconds (100.0%)
     dylib loading time: 927.09 milliseconds (58.8%)
    rebase/binding time:  42.65 milliseconds (2.7%)
        ObjC setup time: 365.58 milliseconds (23.2%)
       initializer time: 239.06 milliseconds (15.1%)
       slowest intializers :
         libSystem.B.dylib :  16.71 milliseconds (1.0%)
libMainThreadChecker.dylib : 111.62 milliseconds (7.0%)
                   ModelIO :  39.38 milliseconds (2.5%)
                 staticpod :  76.22 milliseconds (4.8%)

输出内容展示了系统调用main()函前主要进行的工作内容和时间花费,Session上也对每一阶段加载过程具体内容进行了详细的叙述,有兴趣地可观看该Session.

demo案例

1.新建工程staticpod,添加如下Podfile文件,执行 pod install

platform :ios, '9.0'
#use_frameworks!
use_modular_headers!

target 'staticpod' do
    #OC模块
    pod 'Qiniu'
    pod 'HappyDNS'
    pod 'Masonry'
    pod 'MJRefresh'
    pod 'SDWebImage'
    pod 'MJExtension'
    pod 'pop'
    pod 'FSCalendar'
    pod 'FLAnimatedImage'
    pod 'AFNetworking'

    #swift模块
    pod 'Alamofire'
    pod 'SwiftyJSON'
    pod 'DZNEmptyDataSet'
    pod 'lottie-ios'
    pod 'FileKit'
    pod 'SwiftyUserDefaults'
    pod 'Hero'
end

post_install do |installer|
    installer.pods_project.targets.each do |target|
            target.build_configurations.each do |config|
                config.build_settings['SWIFT_VERSION'] = '4.1'
        end
    end
end

2.在工程的scheme中添加环境变量 DYLD_PRINT_STATISTICS ,设置Value为 1 。App启动加载时就会有启动过程的日志输出,可以查看pre-main时间

3.在工程中添加swift桥接文件 staticpod-Bridging-Header.h ,以支持混编

4.通过添加和删除 use_framework! 对比测试pre-main、ipa大小。PS:测试pre-main时每次请先把App从iphone中删除,避免iphone缓存影响

pre-main测试对比:

//静态库
//第一次:
Total pre-main time: 1.5 seconds (100.0%)
     dylib loading time: 927.09 milliseconds (58.8%)
    rebase/binding time:  42.65 milliseconds (2.7%)
        ObjC setup time: 365.58 milliseconds (23.2%)
       initializer time: 239.06 milliseconds (15.1%)
       slowest intializers :
         libSystem.B.dylib :  16.71 milliseconds (1.0%)
libMainThreadChecker.dylib : 111.62 milliseconds (7.0%)
                   ModelIO :  39.38 milliseconds (2.5%)
                 staticpod :  76.22 milliseconds (4.8%)

//第二次:
Total pre-main time: 1.2 seconds (100.0%)
     dylib loading time: 899.49 milliseconds (72.0%)
    rebase/binding time:  25.12 milliseconds (2.0%)
        ObjC setup time: 222.38 milliseconds (17.8%)
       initializer time: 100.92 milliseconds (8.0%)
       slowest intializers :
         libSystem.B.dylib :  10.80 milliseconds (0.8%)
libMainThreadChecker.dylib :  27.79 milliseconds (2.2%)
                 staticpod :  38.54 milliseconds (3.0%)

//第三次:
Total pre-main time: 1.4 seconds (100.0%)
     dylib loading time: 964.68 milliseconds (67.1%)
    rebase/binding time:  26.76 milliseconds (1.8%)
        ObjC setup time: 300.70 milliseconds (20.9%)
       initializer time: 143.86 milliseconds (10.0%)
       slowest intializers :
         libSystem.B.dylib :  11.79 milliseconds (0.8%)
libMainThreadChecker.dylib :  55.83 milliseconds (3.8%)
                 staticpod :  49.46 milliseconds (3.4%)

//动态库
//第一次:
Total pre-main time: 1.9 seconds (100.0%)
     dylib loading time: 1.5 seconds (81.9%)
    rebase/binding time:  41.20 milliseconds (2.1%)
        ObjC setup time: 184.62 milliseconds (9.4%)
       initializer time: 126.52 milliseconds (6.4%)
       slowest intializers :
         libSystem.B.dylib :  11.67 milliseconds (0.5%)
libMainThreadChecker.dylib :  75.59 milliseconds (3.8%)

//第二次:
Total pre-main time: 2.8 seconds (100.0%)
     dylib loading time: 2.3 seconds (82.7%)
    rebase/binding time:  29.70 milliseconds (1.0%)
        ObjC setup time: 302.37 milliseconds (10.7%)
       initializer time: 153.19 milliseconds (5.4%)
       slowest intializers :
         libSystem.B.dylib :  18.91 milliseconds (0.6%)
libMainThreadChecker.dylib :  58.05 milliseconds (2.0%)

//第三次:
Total pre-main time: 1.7 seconds (100.0%)
     dylib loading time: 1.6 seconds (91.7%)
    rebase/binding time:  41.66 milliseconds (2.3%)
        ObjC setup time:  34.16 milliseconds (1.9%)
       initializer time:  69.59 milliseconds (3.9%)
       slowest intializers :
         libSystem.B.dylib :  13.77 milliseconds (0.7%)

ipa大小对比:

静态库 动态库
97.9MB 103.5MB
  1. 结论:
    1.通过pre-main测试对比发现,在启动时静态库dylib loading time速度明显提升。
    2.通过ipa大小对比发现,静态库比动态库ipa大小有所缩小。

注意事项

1.swift桥接文件

2.swift pod编译需要修改版本

3.在使用静态库时,无法使用 #import <Module/Module-Swift.h> 导入swift文件,必须使用@import Module

参考:
[1]: http://blog.cocoapods.org/CocoaPods-1.5.0/ "Cocoapods 1.5.0更新文档"
[2]: https://blog.csdn.net/khlljm/article/details/52386594 "WWDC之优化App启动速度"
[3]: https://blog.csdn.net/Leemin_ios/article/details/51208642 "#import、#include、@import modules区别"

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335