深入了解替代单纯记忆
本文图片托管在Github上
本文依靠的试验环境:Xcode 13.4.1, Cocoapods 1.11.3
本文首要探寻下Cocoapods是怎么管理不同的library的
阅读本文需求一些前置概念常识:
比方要了解Xcode中project, scheme, target, workspace,还要了解library, framework的概念,能够看下前一篇内容Library, Framework in iOS–Part1
初次履行pod install后Cocoapods会发生ProjectName.xcworkspace,翻开后发现有两个project:ProjectName和Pods
那Cocoapods是怎么将App与Podfile中依靠的library建立依靠关系的呢?
我以一个叫做Test-OC的工程为例来展示,Podfile如下所示:
source 'https://github.com/CocoaPods/Specs.git'
#use_frameworks!
target "Test-OC" do
pod 'lottie-ios'
pod 'MJRefresh'
pod 'AFNetworking', '3.2.0'
end
经过调查工程的Target–Test-OC的依靠关系能够看到:
Test-OC依靠于libPods-Test-OC.a
在Pods这个Project中能够找到Pods-Test-OC
这个target以及其他target
-
Pods-Test-OC
是一个static library - 发现Podfile中依靠的一切library都在Pods的Project中
- 且每个Pod都是static library
到这里咱们能够了解到:Cocoapods创立了一个Pods-Test-OC.a
,然后主工程依靠于该static library
但,现在咱们还不清楚主工程是怎么链接具体的Pod,并且还多了一个问题:
- 主工程的
Link libraries
装备中并没有具体的Pod。主工程仅仅link
了Pods-Test-OC.a
,但Pods-Test-OC
这个target中并没有持续去link
每一个具体的Pod。所以主工程最终是怎么link
具体Pod的 -
Pods-Test-OC
target的效果是什么
咱们在主工程的Build Settings
找到了答案:
能够看到Other Linker Flags
部分增加了对一切Pod的链接指令
原来是在这里链接Pod的,可主工程怎么才干找到每个Pod对应的library呢?
一次偶尔的时机让我大致找到了答案:
在一次履行pod install
时,pod给出了一个正告:
[!] The `Test-OC [Debug]` target overrides the `LIBRARY_SEARCH_PATHS` build setting defined in `Pods/Target Support Files/Pods-Test-OC/Pods-Test-OC.debug.xcconfig'. This can lead to problems with the CocoaPods installation
- Use the `$(inherited)` flag, or
- Remove the build settings from the target.
意思是我的主工程build settings->library search path的装备覆盖了Pods-Test-OC.debug.xcconfig
中library search path的装备。已然这样,那就看下Pods-Test-OC.debug.xcconfig
中library search path的内容吧
LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios" /usr/lib/swift
所以,主工程是经过上面的路径来寻找具体的Pod对应的library的
至此,咱们大概也就猜到了Cocoapods的工作流程:
- Cocoapods将每个Pod创立为一个static library的target
- 构建主工程时,经过修改
Other Linker Flags
和Library Search Path
找到每个static library进行链接
至于另一个问题:Cocoapods为什么要创立了一个名为Pods-ProductName
的target呢?
其实是为了对一切Pod进行统一装备和管理,比方:
- 为主工程装备
Library Search Path
提供数据来历 - 为每个Pod支撑模块导入能力(modular)
其他
use_frameworks!
默许情况下Cocoapods是将每个Pod都创立为static library
的target
Podfile中运用use_frameworks!后,便能够将每个Pod创立为dynamic framework
在Xcode 9之前,Xcode不支撑将用Swift编写的Pod创立为static library
。所以开发者不得不运用use_frameworks!。但假如太多的dynamic framework,或许大概率影响到发动速度
PodName-dummy.m
咱们会在每个Pod的目录下都发现一个Cocoapods为它创立的PodName-dummy.m,其间仅创立了一个名为PodsDummy_PodName
的空类,为什么这么做?
从前出现过这样一个Apple的bug–Building Objective-C static libraries with categories
:当一个library只有category而没有具体的类时,主工程链接library时会出问题,导致运行时调用相应方法时找不到对应实现
对于该问题有两种解决方案:
- 主工程的
Other Link Flags
中参加-ObjC
(其实Cocoapods中也会经过Pods-ProductName
这个target的装备文件为主工程参加) - 另一种便是能够在library中创立一个dummy class,主工程中无需初始化该类的目标,就能让链接正确。但个人测验后发现必须初始化目标才干work
所以,已然苹果主张运用-ObjC
来解决,一起Cocoapods也增加了该符号,为什么依然要创立dummy class呢?
暂时没搞理解
umbrella header
此部分我想对一个有争议的概念聊一下个人看法
当敞开use_frameworks!时,发现每个pod的目录下都会有一个PodName-umbrella.h文件
我在参考资料中了解到,增加该头文件的首要意图是为了让该pod支撑模块导入(modular)能力,即Cocoapods会为该pod创立一个modular.map文件,其间会用到该文件
本文不会对modular进行具体介绍,简单来讲便是让主工程在运用pod时能够经过@import ModuleName
的方法(而非#import <Library/Library.h>
)引进,这种方法更好一些,那这个umbrella.h
便是一个映射–在遇到@import ModuleName
时就会自动相关umbrella.h
中的所写的头文件
争议点在于,有人经过这个命名来得出该pod便是一个umbrella framework,我并不认同,因为umbrella framework是嵌套了其他framework的framework,此处明显不是。我认为仅仅一个一般的头文件,仅仅它包含了该pod中一切的公共头文件引进信息,所以用了一个umbrella单词而已
参考
- Clang Module
- 系统了解 iOS 库与框架
- Objective-C categories in static library