跳转至

Swift指南

编写此文档时最新的发布版本为Swift 5.2

安装Swift

使用Swift的第一步是安装它和依赖包。请前往Download Swift下载安装。为成功运行接下来的例子,请确保在 $PATH 中成功添加了Swift。

** macOS **

安装Xcode即可,Swift已内嵌在Xcode安装包中 输入 swift --version 查看当前版本:

Apple Swift version 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51)
Target: x86_64-apple-darwin19.4.0

** Ubuntu **

安装clang ```shell script $ sudo apt-get install clang

如果您在Linux上将Swift工具链安装到系统根目录以外的目录,则需要使用Swift安装的实际路径运行以下命令:
```shell script
$ export PATH=/path/to/Swift/usr/bin:"${PATH}"

使用REPL

终端输入 swift 即可打开REPL(Read Eval Print Loop)交互式解释器。 ```shell script ~ swift Welcome to Apple Swift version 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51). Type :help for assistance. 1>

尝试一下
```shell script
  1> 1 + 2
$R0: Int = 3
  2> let greeting = "Hello!"
greeting: String = "Hello!"
  3> print(greeting)
Hello!
  4> let numbers = [1,2,3]
numbers: [Int] = 3 values {
  [0] = 1
  [1] = 2
  [2] = 3
}
  5> for n in numbers.reversed(){
  6.     print(n)
  7. }
3
2
1
  8>

尝试导入系统模块

macOS

```shell script 1> import Darwin 2> arc4random_uniform(10) $R0: UInt32 = 4


### Ubuntu
```shell script
1> import Glibc
2> random() % 10
$R0: Int32 = 4

Swift包管理器

Swift包管理器提供了一个基于约定的系统,用于构建库和可执行文件,以及在不同的包之间共享代码。

创建包

```shell script $ mkdir Hello $ cd Hello swift package init

默认情况下,init命令将创建一个库包目录结构:
```text
├── Package.swift
├── README.md
├── Sources
│   └── Hello
│       └── Hello.swift
└── Tests
    ├── HelloTests
    │   └── HelloTests.swift
    └── LinuxMain.swift

你可以使用 swift build 来构建一个包。这将下载、解析和编译manifest文件包中提到的依赖项。 ```shell script $ swift build Compile Swift Module 'Hello' (1 sources)


测试
```shell script
$ swift test
Compile Swift Module 'HelloTests' (1 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/HelloPackageTests.xctest/Contents/MacOS/HelloPackageTests
Test Suite 'All tests' started at 2016-08-29 08:00:31.453
Test Suite 'HelloPackageTests.xctest' started at 2016-08-29 08:00:31.454
Test Suite 'HelloTests' started at 2016-08-29 08:00:31.454
Test Case '-[HelloTests.HelloTests testExample]' started.
Test Case '-[HelloTests.HelloTests testExample]' passed (0.001 seconds).
Test Suite 'HelloTests' passed at 2016-08-29 08:00:31.455.
     Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.001) seconds
Test Suite 'HelloPackageTests.xctest' passed at 2016-08-29 08:00:31.455.
     Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.001) seconds
Test Suite 'All tests' passed at 2016-08-29 08:00:31.455.
     Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.002) seconds

编译可执行包

如果目标文件包含一个名为main.swift的文件,则将其视为可执行文件。包管理器将把该文件编译成二进制可执行文件。

在本例中,该包将生成一个名为Hello的可执行文件,输出“Hello, world!”

```shell script $ mkdir Hello $ cd Hello $ swift package init --type executable


使用swift运行命令来构建和运行可执行文件:
```shell script
$ swift run Hello
Compile Swift Module 'Hello' (1 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/Hello
Hello, world!

注意:由于此包中只有一个可执行文件,我们可以从swift运行命令中省略可执行文件的名称。

您还可以通过运行swift build命令编译包,然后从.build目录运行二进制文件: ```shell script $ swift build Compile Swift Module 'Hello' (1 sources) Linking ./.build/x86_64-apple-macosx10.10/debug/Hello

$ .build/x86_64-apple-macosx10.10/debug/Hello Hello, world!

下一步,让我们在一个新的源文件中定义一个新的 **sayHello(name:)** 函数,并让可执行文件调用它,而不是直接调用 **print(_:)** 。

### 处理多个源文件
在 **Sources/Hello** 目录中新建 **Greeter.swift**,并输入以下代码:    
```swift
func sayHello(name: String) {
    print("Hello, \(name)!")
}

sayHello(name:) 函数接受一个字符串参数并在之前打印“Hello”问候语,用函数参数替换单词“World”。

现在,再次打开 main.swift,将现有内容替换为以下代码:

if CommandLine.arguments.count != 2 {
    print("Usage: hello NAME")
} else {
    let name = CommandLine.arguments[1]
    sayHello(name: name)
}

现在main.swift不再像以前那样使用硬编码的名称,而是从命令行参数中读取。 与直接调用 print(_:) 不同,main.swift 现在调用 sayHello(name:) 方法。 因为该方法是 Hello 模块的一部分,所以不需要 import 语句: ``shell script $ swift run Hellowhoami`


## 使用LLDB调试器

使用LLDB调试器可以逐步运行Swift程序,设置断点,并检查和修改程序状态。

新建 **Factorial.swift**:
```swift
func factorial(n: Int) -> Int {
    if n <= 1 { return n }
    return n * factorial(n: n - 1)
}

let number = 4
print("\(number)! is equal to \(factorial(n: number))")

使用swiftc产生调试信息: ```shell script $ swiftc -g Factorial.swift $ ls Factorial.dSYM Factorial.swift Factorial*


不直接运行Factorial程序,而是通过LLDB调试器将其作为命令行参数传递给LLDB命令来运行它。
```shell script
$ lldb Factorial
(lldb) target create "Factorial"
Current executable set to 'Factorial' (x86_64).

这将启动一个交互式控制台用于运行LLDB命令。

更多调试技巧可参考LLDB Tutorial

factorial(n:) 函数的第2行中使用 breakpoint Set (b) 命令设置一个断点,以便在每次执行该函数时让进程中断。 ``shell script (lldb) b 2 Breakpoint 1: where = FactorialFactorial.factorial (Swift.Int) -> Swift.Int + 12 at Fa


使用 **Run (r)** 命令运行进程。该进程将在 **factorial(n:)** 函数的调用位置停止。
```shell script
(lldb) r
Process 40246 resuming
Process 40246 stopped
* thread #1: tid = 0x14dfdf, 0x0000000100000e7c Factorial`Factorial.factorial (n=4) -> Swift.Int + 12 at Factorial.swift:2, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000e7c Factorial`Factorial.factorial (n=4) -> Swift.Int + 12 at Factorial.swift:2
   1    func factorial(n: Int) -> Int {
-> 2        if n <= 1 { return n }
   3        return n * factorial(n: n - 1)
   4    }
   5
   6    let number = 4
   7    print("\(number)! is equal to \(factorial(n: number))")

使用 print (p) 命令检查n参数的值。 ```shell script (lldb) p n (Int) $R0 = 4


**print** 命令也可以计算Swift表达式。
```shell script
(lldb) p n * n
(Int) $R1 = 16

使用 backtrace (bt) 命令显示导致调用 factorial(n:) 的帧。 ``shell script (lldb) bt * thread #1: tid = 0x14e393, 0x0000000100000e7c FactorialFactorial.factorial (n=4) -> Swift.Int + 12 at Factorial.swift:2, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 * frame #0: 0x0000000100000e7c FactorialFactorial.factorial (n=4) -> Swift.Int + 12 at Factorial.swift:2 frame #1: 0x0000000100000daf Factorialmain + 287 at Factorial.swift:7 frame #2: 0x00007fff890be5ad libdyld.dylibstart + 1 frame #3: 0x00007fff890be5ad libdyld.dylibstart + 1


使用 **continue (c)** 命令继续这个过程,直到再次命中断点为止。
```shell script
(lldb) c
Process 40246 resuming
Process 40246 stopped
* thread #1: tid = 0x14e393, 0x0000000100000e7c Factorial`Factorial.factorial (n=3) -> Swift.Int + 12 at Factorial.swift:2, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000e7c Factorial`Factorial.factorial (n=3) -> Swift.Int + 12 at Factorial.swift:2
   1    func factorial(n: Int) -> Int {
-> 2        if n <= 1 { return n }
   3        return n * factorial(n: n - 1)
   4    }
   5
   6    let number = 4
   7    print("\(number)! is equal to \(factorial(n: number))")

再次使用 print (p) 命令检查第二次调用 factorial(n:) 时n参数的值。 ```shell script (lldb) p n (Int) $R2 = 3


使用 **breakpoint disable (br di)** 命令禁用所有断点,使用 **continue (c)** 命令运行进程,直到它退出。
```shell script
(lldb) br di
All breakpoints disabled. (1 breakpoints)
(lldb) c
Process 40246 resuming
4! is equal to 24
Process 40246 exited with status = 0 (0x00000000)