我把自己学习Swift语法的笔记通过4篇左右的文章分享给大家。由于是个人笔记,代码较多,配的文字很少,对于Swift初学者的理解可能会造成一些困难。
我会在《Swift语法学习笔记》系列中覆盖以下内容:
- Swift常量与变量
- Swift常用数据类型
- 基本数据类型
- 集合类型
- 可选类型
- 流程控制
- if语句
- for循环
- while语句
- repeat语句
- Switch语句
- 函数和闭包
- 函数
- 闭包
- 结构体
- 定义与使用结构体
- 结构体的初始化方法
- 类
- 类
- 继承
本篇是《Swift语法学习笔记》系列的第一篇文章,将涵盖以下内容:
- Swift常量与变量
- Swift常用数据类型
- 基本数据类型
- 整型
- 字符串类型
- 布尔类型
- 枚举类型
- 集合类型
- 数组
- 字典
- Sets
- NSArray、NSDictionary、NSSet
- 可选类型
- Swift郑家可选类型的原因
- 获取可选类型的真实值
- 获取字典中不存在的默认值
- 枚举类型中的可选类型
- as与as!的区别
- as?
- 基本数据类型
1 常量与变量
1.1 常量
Swift使用let声明常量,必须在声明的同时进行初始化赋值,且其值不可更改。
1.2 变量
Swift使用var声明变量:
var str = "Hello World!" //Swift会自动推定str的类型为String,编译器一旦完成类型推定,此后的代码均不可以修改变量的类型
或者
var str : String
str = "Hello World"
2 数据类型
2.1 基本数据类型
2.1.1 Int整型
获取Int数据类型的最小值与最大值:
Int8.min
Int8.max
UInt32.min
UInt32.max
各种进制的表示方法:
let decimal = 123 // Value is 123
let octal = 0o77 // Octal 77 = decimal 63
let hex = 0x1234 // Hex 1234 = decimal 4660
let binary = 0b1010 // Binary 1010 = decimal 10
为了更好的可读性,在赋值时可以使用“_”分隔数字:
let v = -1_234 // Same as -1234
let w = 12_34_56 // Same as 123456
声明常量的同时指定数据类型:
let a = 1.23 // This is inferred to be a Double
let b: Float = 1.23 // Forced to be Float
Swift不可以做如下形式的类型推定:
let a = 123
let b = 0.456
let c = a + b //由于a为Int类型,b为Double类型,所以编译器不能决定c到底是什么类型
若要成功编译,需要将a转换为Double类型
let a = 123
let b = 0.456
let c = Double(a) + b
2.1.2 String类型
使用转译符“\”在字符串中插入双引号:
let quoted = "Contains \"quotes\"" // Contains "quotes"
插入反斜杠:
let backslash = "\\" // Result is \
插入换行符与缩进符:
let specialChars = "Line1\nLine2\tTabbed"
插入数值:
print("The value of pi is \(M_PI)") // Prints "The value of pi is 3.14159265358979\n"
插入表达式:
// This code prints: "Area of a circle of radius 3.0 is 28.2743338823081\n"
let r = 3.0
print("Area of a circle of radius \(r) is \(M_PI * r * r)")
字符串相加:
let s = "That's one small step for man, " + "one giant leap for mankind"
print(s) // "That's one small step for man, one giant leap for mankind\n"
比较字符串:
let s1 = "String one"
let s2 = "String two"
let s3 = "String " + "one"
s1 == s2 // false: strings are not the same
s1 != s2 // true: strings are different
s1 == s3 // true: strings contain the same characters.
获取字符串的长度:
s3.characters.count // 10
s3.utf16.count // 10
字符类型只能包含一个字符,且必须用双引号包围。
let c: Character = "s"
不能使用“+”运算符将字符串与字符相加,需要使用字符串的append方法:
let c: Character = "s"
var s = "Book" // "var" because we want to modify it
s += c // Error – illegal
s.append(c) // "Books"
Swift中的字符串等简单数据类型都是“拷贝类型”(只有类除外,类是“引用类型”):
var s1 = "Book"
var s2 = s1 // s2 is now a copy of s1
s2 += "s" // Appends to s2; s1 is unchanged
s1 // "Book"
s2 // "Books"
2.1.3 Bool类型
var b = true // Inferred type is Bool
var b1: Bool
b1 = false
2.1.4 enum枚举类型
定义枚举类型:
enum DaysOfWeek {
case Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
}
或者
enum DaysOfWeek {
case Sunday
case Monday
case Tuesday
case Wednesday
case Thursday
case Friday
case Saturday
}
var day = DaysOfWeek.Sunday // "day" is inferred to be of type "DaysOfWeek"
day = .Friday // Note that the "." Is required
包含其他数据类型的枚举:
enum Status {
case OK
case ERROR(String)
}
let status = Status.OK
let failed = Status.ERROR("That does not compute") //这里的failed被推定为什么类型?
含有原始值的枚举:
enum DaysOfWeek : Int {
case Sunday = 0 // 0
case Monday // 1
case Tuesday // 2
case Wednesday // 3
case Thursday // 4
case Friday // 5
case Saturday // 6
}
或者
enum DaysOfWeek : Int {
case Sunday = 0
case Monday // 1
case Tuesday // 2
case Wednesday // 3
case Thursday // 4
case Friday = 20 // 20
case Saturday // 21
}
var day = DaysOfWeek.Saturday
let rawValue = day.rawValue // 21 rawValue位Int类型
原始值为字符串的枚举:
enum ResultType : String {
case SUCCESS = "Success"
case WARNING = "Warning"
case ERROR = "Error"
}
let s = ResultType.WARNING.rawValue // s = "Warning"为String类型
通过指定枚举类型的原始值可以获取对应的“枚举值”:
let result = ResultType(rawValue: "Error") // 返回ERROR,result的类型为ResultType?可选类型,具体可以参照“3 可选类型”
2.2 集合类型
2.2.1 数组
声明数组:
var integers = [1, 2, 3]
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
或者
var integers: [Int] // [Int] means "array of Ints"
integers = [1, 2, 3]
空数组
var empty: [String] = []
数组的索引范围:
var integers = [1, 2, 3]
integers[1..<3] // Get elements 1 and 2 as an array. Result is [2, 3]
integers[1..<3] = [4] // Replace elements 1 and 2 with [4]. Result is [1, 4]
integers = [1, 2, 3]
integers[0...1] = [5, 4] // Replace elements 0 and 1 with [5, 4]. Result is [5, 4, 3]
增加新元素:
var integers = [1, 2, 3]
integers.append(4) // Result is [1, 2, 3, 4]
或者
integers.insert(-1, atIndex: 0) // Result is [-1, 1, 2, 3, 4]
或者
var integers = [1, 2, 3]
let a = integers + [4, 5] // a = [1, 2, 3, 4, 5]; integers array unchanged
integers += [4, 5] // Now integers = [1, 2, 3, 4, 5]
删除元素:
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
days.removeAtIndex(3) // Removes "Wednesday" and returns it to the caller
days.removeRange(0..<4) // Leaves ["Friday", "Saturday"]
days.removeAll(keepCapacity: false) // Leaves an empty array
常量数组一旦初始化,不可更改其值:
let integers = [1, 2, 3] // Constant array
integers = [4, 5, 6] // Error: cannot replace the array
integers[0] = 2 // Error: cannot reassign elements
integers.removeAll(keepCapacity: false) // Error: cannot modify content
验证复制特性:
var integers = [1, 2, 3]
var integersCopy = integers // Creates a copy of "integers"
integersCopy[0] = 4 // Does not change "integers"
integers // [1, 2, 3]
integersCopy // [4, 2, 3]
检查数组中是否存在某个值:
let integers = [1, 2, 3]
integers.contains(2) // true
integers.contains(4) // false
获取数组中某个值的索引值:
let integers = [1, 2, 3]
let index = indexOf(3)!.value // Result is 2
2.2.2 字典
声明一个类型为[String, Int](<String, Int>)的字典:
var dict = ["Red": 0,
"Green": 1,
"Blue": 2]
或者
var dict: [String: Int]
dict = ["Red": 0, "Green": 1, "Blue": 2]
获取字典值:
let value = dict["Red"] // Result is 0, the value mapped to the key "Red"
获取字典的键值对总数:
var dict = ["Red": 0, "Green": 1, "Blue": 2]
dict.count // 3
修改字典值:
dict["Yellow"] = 3 // Adds a new value with key Yellow
dict["Red"] = 4 // Updates the value with key Red
删除字典值:
var dict = ["Red": 0, "Green": 1, "Blue": 2]
dict.removeValueForKey("Red") // Removes value with key "Red"
dict.removeAll() // Empties the dictionary
常量字典不能修改:
let fixedDict = ["Red": 0, "Green": 1, "Blue": 2]
fixedDict["Yellow"] = 3 // Illegal
fixedDict["Red"] = 4 // Illegal
fixedDict = ["Blue", 7] // Illegal
fixedDict.removeValueForKey["Red"] // Illegal
2.2.3 集合Sets(无序数组)
声明Set:
let s1 = Set([1, 2, 3])
或者
let s2: Set<Int> = [1, 2, 3]
是否含有某元素:
s1.contains(1) // true
s2.contains(4) // false
s1.count // 3
增加元素:
var s1 = Set([1, 2, 3]) // [2, 3, 1] (note that order does not matter in a set)
s1.insert(4) // [2, 3, 1, 4]
删除元素:
s1.remove(1) // [2, 3, 4]
s1.removeAll() // [] (empty set)
2.2.4 NSArray, NSDictionary and NSSet
声明一个NSString:
let s: NSString = "Red,Green,Blue"
使用NSString:
let s: NSString = "Red,Green,Blue"
let components = s.componentsSeparatedByString(",") // Calls the NSString method
components //[String]类型的["Red", "Green", "Blue"]
使用NSDictionary:
let d = NSDictionary()
强制转换
let e = d as Dictionary
或者
let d = NSDictionary()
let e = d as! [String: String]
2.3 可选类型
2.3.1 Swift增加可选类型的原因
var dict: [String: Int];
dict = ["Red": 0, "Green": 1, "Blue": 2]
let value = dict["Red"] //the inferred type for value is not Int, but Int?—an optional integer
Swift中为什么会增加可选类型呢?考虑这种情况:
let yellowValue = dict["Yellow"]
What value should be assigned to yellowValue? Most languages address this by having a distinguished value that means, by convention, “no value.” In Objective-C, this value is referred to as nil (which is really just a redefinition of 0); in C and C++ it’s NULL (again, a redefinition of 0); and in Java it’s null.
The problem with this is that it can be dangerous to use a nil (or equivalent) value. In Java, for example, using a null reference causes an exception; in C and C++, the application is likely to crash.What's worse, there's no way to know from its declaration whether a variable might contain a null (or nil or NULL) value.
Swift solves this problem in a neat way: it has a nil value, but a variable (or constant) can only be set to nil if it's declared as an optional, or its type is inferred to be optional. As a result, you can tell immediately whether a variable or constant could be nil by examining its type: if it's not optional, it can't be nil. Further to that, Swift requires you to take that into account explicitly whenever you use the value.
不能赋值nil给非可选类型赋值nil:
var color = "Red"
color = nil // Illegal: color is not an optional type.
不能赋值可选类型给非可选类型:
let dict = [0: "Red", 1: "Green", 2: "Blue"]
color = dict[0] // Illegal: value of dict[0] is optional string, color is not optional.
可以将可选类型赋值给可选类型(或者未初始化的常量与变量):
let dict = [0: "Red", 1: "Green", 2: "Blue"]
var color: String? // "String?" means optional String,color的值为nil
color = dict[0] // Legal
print(color) // printed is not“Red” but Optional("Red"),这其实是一个装箱(wrapped)后的值
2.3.2 获取可选类型的值
为了得到可选类型的实际值,需要对可选类型进行Unwrap(拆箱)操作:
let actualColor = color! // "color!" means unwrap the optional, actualColor是String类型
上面的操作其实可以理解为强制拆箱操作,不论其值是否真的存在,这么做其实是很危险的。试看以下操作:
let dict = [0: "Red", 1: "Green", 2: "Blue"]
let color = dict[4] //color是String?类型,其值为nil
let actualColor = color! //对值nil的可选类型进行拆箱,会造成程序崩溃
为了避免发程序崩溃,需要对可选类型进行安全检查:
if color != nil {
let actualColor = color!
}
或者
if let actualColor = color {
// Executed only if color was not nil
print(actualColor)
}
或者
if var actualColor = color {
// Executed only if color was not nil. actualColor can be modified
print(actualColor)
}
或者
if var color = color {
// Executed only if the value of the original color variable was not nil
print(color) // Refers to the new variable, holding the unwrapped value
}
或者
let dict = [0: "Red", 1: "Green", 2: "Blue"]
let color = dict[0]
if var color = color {
// Executed only if color was not nil
print(color) // "Red"
color = "Green" // Reassigns the local variable
} // New color variable is now out of scope
color // Refers to the original value: "Red"
2.3.3 获取字典中不存在的默认值
let dict = [0: "Red", 1: "Green", 2: "Blue"]
let color = dict[4]
let actualColor = color ?? "Blue"
或者
let dict = [0: "Red", 1: "Green", 2: "Blue"]
let actualColor = dict[4] ?? "Blue"
2.3.4 枚举类型中的可选类型
enum ResultType : String {
case SUCCESS = "Success"
case WARNING = "Warning"
case ERROR = "Error"
}
let result = ResultType(rawValue: "Invalid") //result为ResultType?类型,其值为nil
!可选类型的作用:
let dict = [0: "Red", 1: "Green", 2: "Blue"]
var color: String! // Notice the !,这个操作告诉编译器color永远不可能为 nil值
color = dict[0] // Assigns Optional("Red")
print(color) // Automatically unwraps the optional
2.3.5 as与as!的区别
Roughly speaking, you use as when the cast is guaranteed to work and as! when it’s not—the ! expresses the fact that you are forcing the compiler to accept code that it would otherwise report an error for, such as when downcasting.
as可以用于子类向父类的转换:
let s = "Fred"
let n = s as NSString
或者
let label = UILabel()
let view = label as UIView
as!用于父类向子类的强制转换,或未知类向任意类的转换:
let view: UIView = UILabel()
let label = view as! UILabel // Downcast requires !
或者
let d = NSDictionary(objects: ["Red", "Green", "Blue"], forKeys: [0, 1, 2])
let color = d[1] as! String
2.3.6 as?
let d = NSDictionary(objects: ["Red", "Green", "Blue"], forKeys: [0, 1, 2])
获取值:
let color = d[1] // Gets an optional-AnyObject?, wrapping "Green"
或者
let color = d[1] as! String
注意以下的错误代码:
let d = NSDictionary(objects: [ 0, 1, 2], forKeys: [0, 1, 2])
let value = d[1] as! String //crash happened
为了防止这种情况发生,需要使用as?:
The as? operator returns an optional: if its first operand is not of the type given by its second operand, it returns nil instead of crashing
let d = NSDictionary(objects: [ 0, 1, 2], forKeys: [0, 1, 2])
if let value = d[1] as? String { // as? returns nil if d is not of type String?
print("OK") // As expected – use value as normal
} else {
print("Incorrect types") // Executed if d is not of type [Int: String]
}
或者
You can use the is keyword to check whether the dictionary is of the expected type before using it:
if d is [Int: String] { // Evaluate to true if d maps Ints to Strings
print("Is [Int: String]")
} else {
print("Incorrect types")
}
参考文献
《Beginning iPhone Development with Swift 2 - Exploring the iOS SDK 》From page 777 to page 838.
联系作者
- 评论
- xueyublue@gmail.com
- qq905375641
网友评论