CocoaPods介绍
CocoaPods 是开发 OS X 和 iOS 应用程序的一个第三方库的依赖管理工具。利用 CocoaPods,可以定义自己的依赖关系 (称作 pods),并且随着时间的变化,以及在整个开发环境中对第三方库的版本管理非常方便。
CocoaPods 背后的理念主要体现在两个方面。首先,在工程中引入第三方代码会涉及到许多内容。针对 Objective-C 初级开发者来说,工程文件的配置会让人很沮丧。在配置 build phases 和 linker flags 过程中,会引起许多人为因素的错误。CocoaPods 简化了这一切,它能够自动配置编译选项。
其次,通过 CocoaPods,可以很方便的查找到新的第三方库。当然,这并不是说你可以简单的将别人提供的库拿来拼凑成一个应用程序。它的真正作用是让你能够找到真正好用的库,以此来缩短我们的开发周期和提升软件的质量。
核心组件
CocoaPods是用 Ruby 写的,并由若干个 Ruby 包 (gems) 构成的。在解析整合过程中,最重要的几个 gems 分别是:CocoaPods/CocoaPods
, CocoaPods/Core
, 和 CocoaPods/Xcodeproj
(是的,CocoaPods 是一个依赖管理工具 -- 利用依赖管理进行构建的!)。
CocoaPods 是一个 objc 的依赖管理工具,而其本身是利用 ruby 的依赖管理 gem 进行构建的。
CocoaPods/CocoaPod 这是是一个面向用户的组件,每当执行一个 pod 命令时,这个组件都将被激活。该组件包括了所有使用 CocoaPods 涉及到的功能,并且还能通过调用所有其它的 gems 来执行任务。
CocoaPods/Core Core 组件提供支持与 CocoaPods 相关文件的处理,文件主要是 Podfile 和 podspecs。
CocoaPods/Xcodeproj 这个 gem 组件负责所有工程文件的整合。它能够对创建并修改 .xcodeproj 和 .xcworkspace 文件。它也可以作为单独的一个 gem 包使用。如果你想要写一个脚本来方便的修改工程文件,那么可以使用这个 gem。
Ruby 概述
Ruby 的语法具有强大的表现力,并且其使用非常灵活,能快速实现我们的需求,这里简单介绍一下 Ruby 中跟CocoaPods有关的特性。
方法
简单的方法
def method_name (var1=value1, var2=value2) expr..end复制代码
ruby中的方法以'def'
开头,以'end'
作为结尾,我们可以为参数设置默认值,如果方法调用时未传递必需的参数则使用默认值,上例中的value1
和value2
就是默认值。
Ruby 代码在调用方法时可以省略括号。
可变数量的参数
def sample (*test) puts "参数个数为 #{test.length}" for i in 0...test.length puts "参数值为 #{test[i]}" endendsample "Zara", "6", "F"复制代码
以上实例的输出结果为:
参数个数为 3参数值为 Zara参数值为 6参数值为 F复制代码
数据类型--Hash
哈希(Hash)是类似 "key" => "value" 这样的键值对集合。哈希类似于一个数组,只不过它的索引(或者叫"键")不局限于使用数字,Hash 的索引几乎可以是任何对象。
Hash 虽然和数组类似,但却有一个很重要的区别:Hash 的元素没有特定的顺序。 如果顺序很重要的话就要使用数组了。
pod 'SwViewCapture', :git=>'git@github.com:startry/SwViewCapture.git', :branch=>'master'复制代码
def pod(name = nil, *requirements) unless name raise StandardError, 'A dependency requires a name.' end current_target_definition.store_pod(name, *requirements)end复制代码
pod方法后面跟着的参数就是一个Hash的对象,写成key-value的形式就是
{ ":git": "git@github.com:startry/SwViewCapture.git", ":branch": "'master'"}复制代码
block
Ruby 对函数式编程范式的支持是通过 block,Ruby 中的 block 也是一种对象,所有的 Block 都是 Proc 类的实例,也就是所有的 block 可以作为参数传递,返回。
这边构造一个block传参的方法
def target(name, &proc) definition = TargetDefinition.new(name, parent) proc.call() if procend复制代码
除了声明block参数作为参数传入,还可以使用关键字yield在ruby中表示调用块。
yield 主要用于隐式 block 回调,ruby 方法默认可以不声明 block,在其内部可通过 yield 回调。yield 会调用外部传入的 block,block_given? 用于判断当前方法是否传入了 block。
def target(name) definition = TargetDefinition.new(name, parent) yield if block_given?end复制代码
Ruby中do ~end之间的部分称为块,也可以写为{..}
所以这个target方法可以以这种形式调用:
target('PodSample') { pod('SDWebImage', '~> 4.4.2')}复制代码
也可以使用我们常见的形式调用:
target('PodSample') do pod('SDWebImage', '~> 4.4.2')end复制代码
eval
最后一个需要介绍的特性就是 eval 了,早在几十年前的 Lisp 语言就有了 eval 这个方法,这个方法会将字符串当做代码来执行,也就是说 eval 模糊了代码与数据之间的边界,iOS开发过程中也会使用eval执行js代码。
eval "1 + 2 * 3" => 7复制代码
我们在执行Podfile文件的相关操作时,比如常用的install
和update
,都会用eval
在上下文中执行Podfile文件中的“代码”。
Podfile&Podfile.lock的解析
Podfile
在介绍完ruby的语言特性之后,大家对于理解Podfile文件应该没有什么问题了。
CocoaPods内部定义了一些配置方法,把方法参数转化为内部Hash变量的属性。
def source(url) $hash_value['source'] = urlenddef target(target) $hash_value['target'] = targetenddef pod(pod) pods = $hash_value['pods'] pods = [] if pods == nil pods << pod $hash_value['pods'] = podsend复制代码
下面说一下CocoaPods在解析完Podfile的结果是怎么样的。
执行eval(Podfile.content)
的同时会生成一个Podfile类的对象,这个类有重要的两个属性:
- 一个是Hash类型的
internal_Hash
,保存全局的一些配置,比如source
,workspace
。 - 另一个是
TargetDefinition
类的root_target_definitions
对象,TargetDefinition
类之间有parent和children之间的联系,通过root_target_definitions
对象可以遍历到Podfile文件所有声明的target
对象,target
对象会保存传入该target方法中block的所有参数。
Podfile.lock
Podfile.lock文件是用数据描述语言YAML编写的,YAML(YAML Ain’t Markup)是一种简洁的非标记语言,以数据为中心,使用空白,缩进,分行组织数据,从而使得表示更加简洁易读,其可以与json互转,CocoaPods内部是把Podfile.lock文件解析成Hash类型,从而进行参数数据查询和与Podfile文件中的参数进行对比。
看源码发现Cocoapods不仅支持ruby形式的podfile文件,也支持YAML形式的podfile文件配置方式。
PODS: - AFNetworking (3.1.0): - AFNetworking/NSURLSession (= 3.1.0) - AFNetworking/Reachability (= 3.1.0)DEPENDENCIES: - AFNetworking (= 3.1.0)SPEC REPOS: https://github.com/cocoapods/specs.git: - AFNetworkingSPEC CHECKSUMS: AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67PODFILE CHECKSUM: a06ca71d7960a7bf4f294d3ad147e0e67528a467COCOAPODS: 1.5.3复制代码
{ "PODS":[ { "AFNetworking (3.1.0)":[ "AFNetworking/NSURLSession (= 3.1.0)", "AFNetworking/Reachability (= 3.1.0)" ] } ], "DEPENDENCIES":[ "AFNetworking (= 3.1.0)" ], "SPEC REPOS":{ "https://github.com/cocoapods/specs.git":[ "AFNetworking" ] }, "SPEC CHECKSUMS":{ "AFNetworking":"5e0e199f73d8626b11e79750991f5d173d1f8b67" }, "PODFILE CHECKSUM":"a06ca71d7960a7bf4f294d3ad147e0e67528a467", "COCOAPODS":"1.5.3"}复制代码
总的来说ruby形式podfile的解析就是调用方法,把各类参数配置转化为Hash数据,如果是YAML形式的数据转化就更便捷了,本身就是key-value形式的数据。
参考链接: