Swift 起步
原文来自Swift官方网站
查看版本
$ swift --version
Apple Swift version 2.2-dev (LLVM ..., Clang ..., Swift ...)
REPL
如果想运行没有参数的Swift指令,你可以使用REPL(Read-eval-print-loop 交互式解释器),swift的交互解释器可以直接读取、计算、打印你输入的swift代码。
$ swift
Welcome to Apple Swift version 2.2. Type :help for assistance.
1>
- Xcode的Playground正是基于REPL来实时解释运行实现的。
在交互解释器中甚至可以直接引用系统模块,比如Darwin
(Darwin 是MacOS的底层核心):
1> import Darwin
2> arc4random_uniform(10)
$R0: UInt32 = 4
打包指令
Swift的包管理器提供了一整套符合开发者习惯的系统用来构建包、可执行文件、和使用不同的package分享代码。当本地的swift开发包安装完成,你就可以直接调用包管理工具了:swift package, swift run, swift build and swift test
:
$ swift package --help
OVERVIEW: Perform operations on Swift packages
...
1.创建一个包
第一步:创建一个文件夹,命名为Hello:
$ mkdir Hello
$ cd Hello
第二步:每个包都要有一个manifest文件叫做Package.swift
放在根目录,即此时的Hello文件夹。也可以命令生成一个最低配置的包:
swift package init
init命令默认生成如下的包目录结构:
├── Package.swift
├── README.md
├── Sources
│ └── Hello
│ └── Hello.swift
└── Tests
├── HelloTests
│ └── HelloTests.swift
└── LinuxMain.swift
2.构建一个包
然后可以使用swift build
命令来构建一个包,指令会下载、分解、编译配置文件manifest中引入的依赖文件:
swift build
Compile Swift Module 'Hello' (1 sources)
测试运行包: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
3.构建可执行文件
一个构建目标target如果包含了main.swift
那这个target就会被当做一个可执行文件,包管理器会编译这个main文件到一个二进制可执行文件中。
下面做一个栗子,这个包会生成一个叫Hello的可执行文件,执行完成输出“Hello, world!”。
第一步:创建并进入目录
$ mkdir Hello
$ cd Hello
第二步:初始化包,指定为可执行文件类型
swift package init --type executable
第三步:使用swift run
指令构建并执行上面初始化后的可执行文件
swift run Hello
- 提示:由于这个包目录里只有一个可执行文件,我们可以省略执行文件的名字,直接使用
swift run
。
你也可以先用swift build
命令先编译这个包,再在 .build 目录下运行二进制文件:
$ 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:)
,并让可执行文件来执行我们定义的这个方法。
构建接收外部参数的包
第一步:在Sources/Hello
目录创建一个新文件Greeter.swift
,输入如下代码:
func sayHello(name: String) {
print("Hello, \(name)!")
}
- 这个
sayHello(name:)
方法接收一个字符串作为参数并拼接"Hello, "后打印。
第二步:打开main.swift
文件,替换里面的代码为:
if CommandLine.arguments.count != 2 {
print("Usage: hello NAME")
} else {
let name = CommandLine.arguments[1]
sayHello(name: name)
}
比起之前用硬编码的方式,main.swift
现在从命令行读取参数,并传入sayHello(name:)
方法中处理后再输出。
第三步:再次运行swift run
,生成新版本的Hello执行文件:
$ swift run Hello `whoami`
- 如需要学习Swift包管理器,包括怎么构建模块、引入依赖和索引到系统自带的库,请参考Swift Package Manager。
使用 LLDB 调试器
可以使用LLDB
调试器一步一步运行swift程序,设置断点,检查和修改程序状态。
举个栗子,以下代码定义了一个factorial(n:)
方法,调用后打印执行结果:
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))")
创建一个Factorial.swift
文件,将上面的代码copy到文件,然后运行swiftc
命令,把这个文件的文件名作为参数,跟一个-g
选项来生成调试信息。执行后会在当前目录生成一个名为Factorial的可执行文件。
$ swiftc -g Factorial.swift
$ ls
Factorial.dSYM
Factorial.swift
Factorial(Unix可执行文件)
使用swiftc
命令(类似javac和gcc的编译工具)编译swift文件同时可以输出编译信息。然后,我们不适用run
指令直接执行程序,而是换成LLDB来运行,使用LLDB调试器需要把程序作为参数输入lldb指令后面:
$ lldb Factorial
(lldb) target create "Factorial"
Current executable set to 'Factorial' (x86_64).
(lldb) ...等待输入调试指令...
然后会出现一个交互式控制台让我们来运行lldb命令。
- 更多LLDB信息请参考LLDB Tutorial.。
使用b
指令(breakpoint set)在factorial(n:)
方法的第二行设置断点,然后每次执行到这一行代码时都会获取到程序间歇。
(lldb) b 2
Breakpoint 1: where = Factorial`Factorial.factorial (Swift.Int) -> Swift.Int + 12 at Factorial.swift:2, address = 0x0000000100000e7c
使用r
指令(run)运行程序,输入r并回车以后程序会运行起来并停止在factorial(n:)
方法的调用栈:
(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))")
使用p
指令(print)来查看参数 n 的值:
(lldb) p n
(Int) $R0 = 4
-
p
指令也能计算swift表达式:
(lldb) p n * n
(Int) $R1 = 16
使用bt
指令(backtrace)来查看通向factorial(n:)
的框架:
(lldb) bt
* thread #1: tid = 0x14e393, 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
frame #1: 0x0000000100000daf Factorial`main + 287 at Factorial.swift:7
frame #2: 0x00007fff890be5ad libdyld.dylib`start + 1
frame #3: 0x00007fff890be5ad libdyld.dylib`start + 1
使用c
指令(continue)来继续程序,直到遇到下一个断点:
(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))")
再次使用p
指令来查看参数 n 的值:
(lldb) p n
(Int) $R2 = 3
使用br di
指令(breakpoint disable)关闭所有断点,然后用c
指令继续程序:
(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)
#结语
现在已经介绍完了Swift的REPL、构建系统、调试器,如果需要更深一步的学习,这里有一些建议供参考: