Swift的特色是安全、快速、跨平台。
这是学习Swift语言的入门教材,一般都需要花时间读一下。中文版容易理解一点,英文版更新及时一点,两者对照一下吧。
中文版
英文版
常量和变量-Constants and Variables
声明常量和变量-Declaring Constants and Variables
- 常量和变量必须在使用前声明,用let来声明常量,用var来声明变量。
- 在编程时,推荐养成这样的习惯:默认用let,需要时才改为var
- 从语言的使用习惯上来说,在OC或者C中,会经常在类型前面添加const关键字吗?在实际的Swift编程中,let的数量将超过var,是不是更加“安全”?
- 语句末尾可以不加“;”,同一行多条语句之间的“;”必须加,否则没法区分
- 末尾的“;”加了也不会错,不过习惯上不加,省事
- 习惯上一行只写一条语句,末尾的“;”省略掉
- 可以在一行中声明多个常量或者多个变量,用逗号隔开:
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
var x = 0.0, y = 0.0, z = 0.0
类型标注-Type Annotations
- 添加类型标注,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称
- 有类型推断功能,一般类型都默认不写,必要的时候才加。 比如CG开头那些一般都需要加的,CGFloat(浮点数是被推断为Double)
- OC的类型要前置,不能省略;Swift的类型后置,并且要加“:”,从书写习惯上鼓励省略
- Swift是静态强类型,如果不能从值推断出类型,必须通过“:”指定类型
var welcomeMessage: String
var red, green, blue: Double
常量和变量的命名-Naming Constants and Variables
- 可以用任何你喜欢的字符作为常量和变量名,包括 Unicode 字符:
- 实际中,习惯上还是用英文来命名
- 是否用中文命名,值得商榷
- 是否用数学符号命名,值得商榷,比如常用“PI”
let π = 3.14159
let 你好 = "你好世界"
let 🐶🐮 = "dogcow"
打印常量和变量-Printing Constants and Variables
- 可以用print函数来输出当前常量或变量的值
- Swift 用字符串插值(string interpolation)的方式把常量名或者变量名当做占位符加入到长字符串中,Swift 会用当前常量或变量的值替换这些占位符。将常量或变量名放入圆括号中,并在开括号前使用反斜杠将其转义“\()”
- [重识Xcode 7 Beta 6中的Print功能]
(http://www.cocoachina.com/ios/20150827/13246.html)- NSLog尽量不要用了,优先考虑Swift语言本身提供的库函数
- 格式化字符串可以用在String的构造函数中
// print函数,console中输出log
var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonjour!"
print(friendlyWelcome)
print("The current value of friendlyWelcome is \(friendlyWelcome)")
// 格式化输出
let formatString = String(format: "Name: %3.2f \n Date: %@", 8974.008, "b")
print(formatString)
注释-Comments
- 多行注释可以嵌套在其它的多行注释之中
/* 这是第一个多行注释的开头
/* 这是第二个被嵌套的多行注释 */
这是第一个多行注释的结尾 */
整数-Integers
- 可以访问不同整数类型的min和max属性来获取对应类型的最小值和最大值
- Swift中基本类型都是结构体struct,可以包含属性和方法
- 默认情况下,习惯上用Int,长度与当前平台的原生字长相同
- 必要情况,特定情况下,考虑用UInt,Int64等类型
let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8
let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8
浮点数-Floating-Point Numbers
- Double表示64位浮点数。当前64位架构默认类型
- Float表示32位浮点数。精度要求不高的话可以使用此类型。
- 默认情况下,使用Double
- 必要情况下使用Float
- 在当前的64位架构下,CGFloat也以Double为默认类型了
public struct CGFloat {
/// The native type used to store the CGFloat, which is Float on
/// 32-bit architectures and Double on 64-bit architectures.
public typealias NativeType = Double
public init()
public init(_ value: Float)
public init(_ value: Double)
/// The native value.
public var native: NativeType
}
数值型字面量-Numeric Literals
- 数值类字面量可以包括额外的格式来增强可读性。整数和浮点数都可以添加额外的零并且包含下划线,并不会影响字面量
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
整数字面量-Integer literals
- 十进制数,没有前缀
- 二进制数,前缀是0b
- 八进制数,前缀是0o
- 十六进制数,前缀是0x
let decimalInteger = 17
let binaryInteger = 0b10001 // 二进制的17
let octalInteger = 0o21 // 八进制的17
let hexadecimalInteger = 0x11 // 十六进制的17
浮点字面量-Floating-point literals
- 十进制数,没有前缀
- 十六进制数,前缀是0x
- 十进制浮点数也可以有一个可选的指数(exponent),通过大写或者小写的 e 来指定。如果一个十进制数的指数为exp,那这个数相当于基数和10^exp的乘积。
- 十六进制浮点数必须有一个指数,通过大写或者小写的 p 来指定。如果一个十六进制数的指数为exp,那这个数相当于基数和2^exp的乘积。
// 下面的这些浮点字面量都等于十进制的12.1875:
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0
- Floating point hex notation in Swift
- 0xC.3p0 = (12 + 3/16) * 2^0 = 12.1875
- 0xAB.CDp4 = (10*16 + 11 + 13/16 + 14/16^2) * 2^4 = 2748.8125
数值型类型转换-Numeric Type Conversion
- 通常来讲,即使代码中的整数常量和变量已知非负,也请使用Int类型。总是使用默认的整数类型可以保证你的整数常量和变量可以直接被复用并且可以匹配整数类字面量的类型推断。
- 默认用类型推断
- 默认原生类型,比如Int,Double,String等
- 只有在必要的时候才使用其他整数类型,比如要处理外部的长度明确的数据或者为了优化性能、内存占用等等。使用显式指定长度的类型可以及时发现值溢出并且可以暗示正在处理特殊数据。
- 调试蓝牙传输的时候,就用到过UInt8,UInt16,UInt32,UInt64等类型
Integer Conversion
- SomeType(ofInitialValue)是调用 Swift 构造器并传入一个初始值的默认方法
- Int, UInt, Double等都是结构体struct,有构造函数,属性,方法等
// 如果类型不同,将不能相加
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
整数和浮点数转换-Integer and Floating-Point Conversion
- 整数和浮点数的转换必须显式指定类型:
// pi 等于 3.14159,所以被推测为 Double 类型
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
- 浮点数到整数的反向转换同样行,整数类型可以用Double或者Float类型来初始化:
// integerPi 等于 3,所以被推测为 Int 类型
let integerPi = Int(pi)
- 字面量3可以直接和字面量0.14159相加,因为数字字面量本身没有明确的类型。它们的类型只在编译器需要求值的时候被推测。
// doublePi 等于 3.14159,所以被推测为 Double 类型
let doublePi = 3 + 0.14159
和C语言用()进行强制转换不同,Swift实际上是调用了构造函数,重新生成了新的结构体struct,并没有进行真正的强制转换。
类型别名-Type Aliases
- 使用typealias关键字来定义类型别名
// maxAmplitudeFound is now 0
typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min
布尔值-Booleans
- Swift 有一个基本的布尔(Boolean)类型,叫做Bool。布尔值指逻辑上的值,因为它们只能是真或者假。Swift 有两个布尔常量,true和false
OC中是YES,NO
- 如果你在需要使用Bool类型的地方使用了非布尔值,Swift 的类型安全机制会报错
OC和C中有这种用法
let i = 1
if i == 1 {
// 这个例子会编译成功
}
if i {
// 这个例子不会通过编译,会报错
}
元组-Tuples
- 元组(tuples)把多个值组合成一个复合值。元组内的值可以是任意类型,并不要求是相同类型。
元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用,请使用类或者结构体而不是元组。
let http404Error = (404, "Not Found")
// http404Error 的类型是 (Int, String),值是 (404, "Not Found")
可选类型-Optionals
- 使用可选类型(optionals)来处理值可能缺失的情况。本质是一种枚举。
- 有值,等于 x
- 没有值,nil
nil
- nil不能用于非可选的常量和变量。
- nil不是指针——它是一个确定的值,用来表示值缺失。
在 Objective-C 中,nil是一个指向不存在对象的指针。
- 任何类型的可选状态都可以被设置为nil,不只是对象类型。Int?,Double?等都是结构体struct,不是对象,都可以是nil
if 语句以及强制解析-If Statements and Forced Unwrapping
- 强制解析: 可选变量后面加个“!”
- 含义:“我知道这个可选有值,请使用它。”
- 如果值不存在,而用了“!”取值,程序崩溃
- Xcode中用Storyboard或者xib拉的输出口IBOutlet是用“!”的。
- 其他地方尽量就不要用“!”,宁可多写一点
可选绑定-Optional Binding
- 使用可选值可以用下面的经典结构
if let constantName = someOptional {
// statements
}
- 可以把多个可选值一次解析,还可以加上where条件判断
if let firstNumber = Int("4"), secondNumber = Int("42") where firstNumber < secondNumber {
print("\(firstNumber) < \(secondNumber)")
}
// Prints "4 < 42"
- 解包后的值变量作用域是if后的{},所以实际使用时,解包的变量名和可选变量名可以完全一致(解决取名字的麻烦,偷懒取巧的做法)
- guard关键字的作用域是语句后到函数结束,这很好理解。解包变量和可选变量仍然可以用相同名字。虽然名字一样,不过guard之后,肯定有值,不会崩溃,放心使用。(解决取名字的麻烦,偷懒取巧的做法)
隐式解析可选类型-Implicitly Unwrapped Optionals
- 声明的时候用“!”,不用“?”
- 可以当做普通类型来使用,不需要if解包,或者用“!”,可以直接使用
- 也可以当做普通可选类型用,不嫌麻烦的话,可以用if解包后再使用
- 本质上是可选类型,可以接受nil,但是被设为nil的话,程序崩溃
- 主要用在框架设计中,少写几次if let {} 结构,偷懒用的
- 框架设计中,如果怕框架使用者忘记对这个变量赋值,可以考虑这种用法(最直接的崩溃提醒使用者)
- 一般情况,强烈不建议这种用法。要么普通变量,不用考虑nil;要么?定义普通可选变量,老老实实if let {} 解包,防止崩溃
// 普通可选类型,用?定义
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark
// 隐式可选类型,用!定义
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation mark
错误处理-Error Handling
- 函数定义之处用throws标注
- 使用时用 do try catch 结构
func canThrowAnError() throws {
// 这个函数有可能抛出错误
}
do {
try canThrowAnError()
// 没有错误消息抛出
} catch {
// 有一个错误消息抛出
}
- 错误处理的函数定义和调用之处都需要特殊的标注,提醒需要特别注意。
- 错误处理流程会破坏程序的顺序执行流程
- 除非必要,一般不要引入错误处理