Swift 中的模块依赖管理

Swift 中的模块依赖管理_第1张图片
CocoaPods

提起CocoaPods 和 Carthage , iOS的开发者应该不会陌生,作为iOS 项目开发中的模块依赖管理工具,可以自动实现依赖模块的下载,编译和链接。 Swift 社区在3.0版本以后内置了类似工具 - Swift Package Manager,有了Apple官方的支持,相信未来会大放异彩。

模块依赖

模块化带来的一个重要好处就是复用,开发者不用重复去制造已经存在的轮子,从而站在巨人的肩膀上做更有意义的事。如网络模块可以在电商应用中使用,也可以在社交应用中使用。

Swift项目中按照模块(Modules)分组,每个模块需要定义命名空间,且声明模块内的哪些类和方法允许被外部访问。

一个模块有可能已经包含运行需要的所有内容,也可能需要依赖引入第三方模块。除了系统层面的模块,如macOS中的Darwin,或Linux中的Glibc,更多的依赖是需要远程下载且按顺序编译的模块。

每个程序包(package)包括Swift源代码文件和资源配置(Manifest)文件, 每个资源配置文件命名为Package.swift,在文件内要定义包名和其他内容,且依赖于模块PackageDescription。

参看下面的例子,每个package有一到多个targets,每个target 有一到多个模块依赖。

import PackageDescription

let package = Package(
    name: "dealer",
    products: [
        .executable(name: "Dealer", targets: ["Dealer"]),
    ],
    dependencies: [
        // 依赖
        .package(url: "https://github.com/apple/example-package-deckofplayingcards.git", from: "3.0.0"),
    ],
    targets: [
        .target(
            name: "Dealer",
            dependencies: ["DeckOfPlayingCards"]),
    ]
)

注意上述案例中的products界面可以声明为executable 或library。

  • library指能被其他Swift引用的模块,不能被操作系统直接运行。
  • executable 指程序可以被操作系统直接运行。

模块依赖顾名思义是指模块在其他程序中被引用,依赖的内容包括相对程序的路径或绝对路径和版本号。注意模块依赖的过程是递归的,一个被依赖的模块可以有自己的依赖集合。

而模块管理就是通过工具让下载和编译依赖模块的过程自动化,降低人工管理成本。

案例

我们通过官方提供的案例来看看如何使用Swift Package Manager。

PlayingCard - library类型模块 https://github.com/apple/example-package-playingcard
FisherYates - library类型模块 https://github.com/apple/example-package-fisheryates

下载到本地可以查看文件结构:

example-package-playingcard
├── Sources
│   └── PlayingCard
│       ├── PlayingCard.swift
│       ├── Rank.swift
│       └── Suit.swift
└── Package.swift

注意 library类型模块只能被其他Swift引用,不能被操作系统直接运行。

DeckOfPlayingCards 虽然是library模块,但其代码内依赖其他library模块,https://github.com/apple/example-package-deckofplayingcards

// swift-tools-version:4.0
import PackageDescription

let package = Package(
    name: "DeckOfPlayingCards",
    products: [
        .library(name: "DeckOfPlayingCards", targets: ["DeckOfPlayingCards"]),
    ],
//依赖
    dependencies: [
        .package(url: "https://github.com/apple/example-package-fisheryates.git", from: "2.0.0"),
        .package(url: "https://github.com/apple/example-package-playingcard.git", from: "3.0.0"),
    ],
    targets: [
        .target(
            name: "DeckOfPlayingCards",
            dependencies: ["FisherYates", "PlayingCard"]),
        .testTarget(
            name: "DeckOfPlayingCardsTests",
            dependencies: ["DeckOfPlayingCards"]),
    ]
)

Dealer - executable模块
https://github.com/apple/example-package-dealer
其依赖DeckOfPlayingCards模块,而DeckOfPlayingCards模块依赖PlayingCard 和 FisherYates 模块,但模块管理工具让开发者只需关心DeckOfPlayingCards模块即可,间接依赖工具都会自动解决。

import PackageDescription

let package = Package(
    name: "dealer",
    products: [
        .executable(name: "Dealer", targets: ["Dealer"]),
    ],
    dependencies: [
        .package(url: "https://github.com/apple/example-package-deckofplayingcards.git", from: "3.0.0"),
    ],
    targets: [
        .target(
            name: "Dealer",
            dependencies: ["DeckOfPlayingCards"]),
    ]
)

executable模块默认地使用main.swift 作为执行程序入口。

通过命令swift build 调用编译系统生成可执行文件Dealer,位于.build/debug文件夹下。

$ swift build
$ ./.build/debug/Dealer
♠︎6
♢K
♢2
♡8
♠︎7
♣︎10
♣︎5
♢A
♡Q
♡7
推荐阅读

获取更多内容请关注微信公众号豆志昂扬:

  • 直接添加公众号豆志昂扬
  • 微信扫描下图二维码;

你可能感兴趣的:(Swift 中的模块依赖管理)