Build a library

The source code for this guide can be found on GitHub

安装 Swift

要开始您的旅程,请 安装 Swift 开始在 macOSLinuxWindows 上使用它。

提示: 要测试是否已安装 Swift,请在 shell 或终端应用程序中运行 swift --version

Swift 捆绑了 Swift 包管理器(SwiftPM),用于管理 Swift 代码的发布。它允许将其他 Swift 包轻松导入到您的应用程序和库中,因此是所有 Swift 开发人员的重要工具。

Swift 遵循 Apache License, 版本 2.0

Bootstrapping

Let’s write a small library with our new Swift development environment. To start, we’ll use SwiftPM to make a new project for us. In your terminal of choice run:

$ mkdir MyLibrary
$ cd MyLibrary
$ swift package init --name MyLibrary --type library

This will generate a new directory called MyLibrary with the following files:

.
├── Package.swift
├── Sources
│   └── MyLibrary
│       └── MyLibrary.swift
└── Tests
    └── MyLibraryTests
        └── MyLibraryTests.swift

Package.swift is the manifest file for Swift. It’s where you keep metadata for your project, as well as its dependencies.

Sources/MyLibrary/MyLibrary.swift is the library initial source file and where we’ll write our library code. Test/MyLibraryTests/MyLibraryTests.swift is where we can write tests for our library.

In fact, SwiftPM generated a “Hello, world!” project for us, including some unit tests! We can run the tests by running swift test in our terminal.

$ swift test
Building for debugging...
[5/5] Linking MyLibraryPackageTests
Build complete! (7.91s)
Test Suite 'All tests' started at 2023-08-29 18:59:31.328
Test Suite 'MyLibraryPackageTests.xctest' started at 2023-08-29 18:59:31.329
Test Suite 'MyLibraryTests' started at 2023-08-29 18:59:31.329
Test Case '-[MyLibraryTests.MyLibraryTests testExample]' started.
Test Case '-[MyLibraryTests.MyLibraryTests testExample]' passed (0.001 seconds).
Test Suite 'MyLibraryTests' passed at 2023-08-29 18:59:31.330.
	 Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.001) seconds
Test Suite 'MyLibraryPackageTests.xctest' passed at 2023-08-29 18:59:31.330.
	 Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.001) seconds
Test Suite 'All tests' passed at 2023-08-29 18:59:31.330.
	 Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.002) seconds

A small library

Now let’s write a small library. Replace the example content of MyLibrary.swift with the following code:

import Foundation

struct Email: CustomStringConvertible {
  var description: String

  public init(_ emailString: String) throws {
    let regex = #"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,64}"#
    guard let _ = emailString.range(of: regex, options: .regularExpression) else {
      throw InvalidEmailError(email: emailString)
    }
    self.description = emailString
  }
}

private struct InvalidEmailError: Error {
  let email: String
}

Now let’s add a unit test for this strongly typed Email API. Replace the example content of MyLibraryTests.swift with the following code:

@testable import MyLibrary
import XCTest

final class MyLibraryTests: XCTestCase {
  func testEmail() throws {
    let email = try Email("[email protected]")
    XCTAssertEqual(email.description, "[email protected]")

    XCTAssertThrowsError(try Email("invalid"))
  }
}

Once we save that, we can run the tests again:

❯ swift test
Building for debugging...
[5/5] Linking MyLibraryPackageTests
Build complete! (3.09s)
Test Suite 'All tests' started at 2023-08-29 19:01:08.640
Test Suite 'MyLibraryPackageTests.xctest' started at 2023-08-29 19:01:08.641
Test Suite 'MyLibraryTests' started at 2023-08-29 19:01:08.641
Test Case '-[MyLibraryTests.MyLibraryTests testEmail]' started.
Test Case '-[MyLibraryTests.MyLibraryTests testEmail]' passed (0.002 seconds).
Test Suite 'MyLibraryTests' passed at 2023-08-29 19:01:08.643.
	 Executed 1 test, with 0 failures (0 unexpected) in 0.002 (0.002) seconds
Test Suite 'MyLibraryPackageTests.xctest' passed at 2023-08-29 19:01:08.643.
	 Executed 1 test, with 0 failures (0 unexpected) in 0.002 (0.002) seconds
Test Suite 'All tests' passed at 2023-08-29 19:01:08.643.
	 Executed 1 test, with 0 failures (0 unexpected) in 0.002 (0.003) seconds

The source code for this guide can be found on GitHub