字符
- 字符:是字符串的基本组成单位。
格式:
let/var 名称: Character = "值"
let ch: Character = "A"
print(ch)
- 转义字符:具有特殊含义的字符。
转义字符 | 说明 |
---|---|
\t | 水平制表符 tab |
\n | 换行 |
\r | 回车 |
\" | 双引号 |
\' | 单引号 |
\\ | 反斜线 |
- 编码:Swift 采用 Unicode 编码,几乎涵盖一切字符,包括 emoji 表情。
字符串
区别
在 OC 中 NSString 是一个对象;
在 Swift 中 String 是一个结构体,且不能再被看作是一个 Collection 类型。
创建字符串
1. 通过创建 String 实例方式
let anotherString = String()
if anotherString.isEmpty {
print("什么都没有")
}
2. 通过字面量赋值方式
let tempString = "this is temp string"
print(tempString)
- 常见操作
1. 获取字符串的长度
let string = "Swift is fun."
let length = string.characters.count
print(length)
2. 遍历字符串
(1) // for-in遍历
let string = "Swift is fun."
for c in string.characters {
print(c)
}
(2) // enumerated 方法返回一个tuple序列
let mixStr = "Swift很有趣"
for (index, value) in mixStr.characters.enumerated() {
print("\(index): \(value)")
}
3. 字符串之间的操作
(1) 使用加法赋值运算符连接字符串
var varString = "bookuu"
varString += ".com"
print(varString)
(2) 使用加法运算符拼接字符串
let string1 = "你好"
let string2 = "博库"
let string3 = string1 + string2
print(string3)
(3) 字符串和其它标识符之间的拼接 \()
let name = "qzy"
let age = 18
let height = 1.88
let infoString = "my name is \(name), age is \(age), height is \(height)!"
print(infoString)
(4) 调用 append 方法追加一个字符
var string = "你好,博库"
let character: Character = "!"
string.append(character)
print(string)
4. 截取字符串
(1) 将 String 转换为 NSString 来截取字符串
let string = "hello, bookuu!"
let subString = (string as NSString).substring(with:NSMakeRange(1, 5))
print(subString)
(2) 用 Swift 方法来截取字符串
1. 在 Swift 中,String 有 unicodeScalar、utf8、utf16、CharacterView 四种 View;
2. View 就是告诉 String 类型如何去理解字符串中的内容,它们是 String 的不同属性;
3. CharacterView 只能顺序向前,或者向后移动,而不能随机指定位置移动。
// 截取指定索引字符串
let cafee = "caf\u{0065}\u{0301}"
// 1. Get character Index
let index = cafee.index(cafee.startIndex, offsetBy: 3)
// 2. Subscript access
let subString = cafee[index];
let subString1 = cafee[cafee.startIndex...index]
let subString2 = String(cafee.characters.prefix(3))
let subString3 = String(cafee.characters.suffix(2))
print(subString, subString1, subString2, subString3)
// 根据指定字符切片分段
var mixString = "Swift 3.0 is interesting!"
let splitArray = mixString.characters.split(separator: " ").map(String.init)
print(splitArray)
5. 插入字符串
var mixString = "Swift很有趣"
if let index = mixString.characters.index(of: "很") {
mixString.insert(contentsOf: "3.0".characters, at: index)
print(mixString)
}
6. 删除字符串
// 在一个字符串的指定索引处删除一个字符
var welcome = "hello, there!"
welcome.remove(at: welcome.index(before: welcome.endIndex))
print(welcome)
// 在一个字符串的指定索引处删除一个子字符串
var welcome = "hello, there!"
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
print(welcome)
7. 替换字符串
var mixString = "Swift很有趣"
if let cnIndex = mixString.characters.index(of: "很") {
mixString.replaceSubrange(cnIndex..<mixString.endIndex, with: " is interesting!")
print(mixString)
}
8. 包含字符串
* 用 contains(_:) 判断字符串是否包含某个字符或者字符串
9. 格式字符串
let hour = 8
let minute = 5
let seconds = 6
// 按照 format 的格式来显示 arguments 的内容
let dateString = String(format:"%02d:%02d:%02d", arguments: [hour, minute, seconds])
print(dateString)
// 按照 format 的格式拼接hour、minute、seconds 的 内容
let dateStirng1 = String(format:"%02d:%02d:%02d", hour, minute, seconds)
print(dateStirng1)
10. 比较字符串
(1) 用 == 和 != 比较字符或者字符串是否相等
(2) 用 hasPrefix(_:) 和 hasSuffix(_:) 比较字符串的前缀或者后缀
数组
- array:数组是一组存储有序且类型相同数据的集合;数组中的数据被称作元素。
- 创建数组
1. 创建一个空数组
var someInts = [Int]()
someInts.append(3)
if someInts.isEmpty {
print("The someInts list is empty")
}
// 代码上下文中已经提供类型信息,可以使用空的数组字面量创建一个空数组
someInts = []
2. 用数组字面量构造数组
(1) let 常量名: [类型] = [value1, value2, value3,...]
let array: [String] = ["Hello", "Hi"]
(2) let 常量名 = [value1, value2, value3,...]
let array1 = ["zhangsan", "18"]
3. 创建一个带有默认值的数组
let threeDoubles = Array(repeating: 0.0, count: 3)
print(threeDoubles)
- 常见操作
1. 获取数组的长度
let season: [String] = ["春", "夏", "秋", "冬"]
let length = season.count
print(length)
2. 遍历数组
(1) 可以获取到下标值
let arrayM = ["wxx", "ljj", "yz", "qxb"]
for i in 0..<arrayM.count {
print(array[i])
}
(2) 不用下标值
let arrayM = ["wxx", "ljj", "yz", "qxb"]
for name in arrayM {
print(name)
}
(3) 可以获取到下标值,也可以直接获取到元素
let arrayM = ["wxx", "ljj", "yz", "qxb"]
for (i, name) in arrayM.enumerated() {
print(i, name)
}
3. 数组之间的操作
(1) 使用加法赋值运算符连接数组
var shoppingList = ["Eggs", "Milk"]
shoppingList += ["Baking Powder"]
print(shoppingList)
(2) 使用加法运算符拼接数组
let array1 = ["wxx", "ljj"]
let array2 = ["yz", "qxb"]
let resultArray = array1 + array2
print(resultArray)
(3) 调用 append 方法追加一个元素
var arrayM = ["wxx", "ljj"]
arrayM.append("qxb")
4. 获取元素
let arrayM = ["wxx", "ljj", "yz", "qxb"]
let item = arrayM[0]
let item1 = arrayM[0...1]
print(item, item1)
5. 插入元素
var arrayM = ["wxx", "ljj", "yz"]
arrayM.insert("qxb", at: 2)
print(arrayM)
6. 删除元素
var arrayM = ["wxx", "ljj", "yz", "qxb"]
// 删除第一个元素
arrayM.removeFirst()
print(arrayM)
// 删除最后一个元素
arrayM.removeLast()
print(arrayM)
// 删除指定位置的元素
array.remove(at: 1)
print(arrayM)
// 删除所有元素,并且保留存储空间
arrayM.removeAll(keepingCapacity: true)
print(arrayM)
7. 替换元素
var arrayM = ["wxx", "ljj", "qxb", "chs", "jxd"]
// 使用下标语法修改1个元素
arrayM[1] = "yz"
print(arrayM)
// 使用下标语法修改多个元素
arrayM[2...3] = ["zzy"]
print(arrayM)
// 使用下标语法修改多个元素
arrayM[2...3] = ["lj", "pmj"]
print(arrayM)
8. 包含元素
* 用 contains(_:) 判断数组是否包含某个元素
集合
Set:用来存储相同类型并且没有确定顺序的值。
- Set 里面的元素是无序的;
- 每个元素都不能重复。
创建集合
1. 创建一个空集合
var letters = Set<Character>()
print ("letters is of type Set<Character> with \(letters.count) items.")
letters.insert("a")
if letters.isEmpty {
print("The letters is empty.")
}
// 代码上下文中已经提供类型信息,可以通过一个空的数组字面量创建一个空的 Set
letters = []
2. 用数组字面量创建集合
(1) let 常量名: Set<类型> = [value1, value2, value3,...]
let favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
(2) let 常量名: Set = [value1, value2, value3,...]
let favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
- 常见操作
1. 获取集合的长度
let favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
let count = favoriteGenres.count
print(count)
2. 遍历集合
(1) 无序遍历
let favoriteColors: Set = ["Hip hop", "Jazz", "Classical"]
for genre in favoriteColors {
print(genre)
}
(2) 有序遍历:调用 sorted() 方法返回一个有序数组;数组的元素排列顺序由操作符 < 对元素进行比较的结果来确定
let favoriteColors: Set = ["Hip hop", "Jazz", "Classical"]
for genre in favoriteColors.sorted() {
print("\(genre)")
}
3. 添加元素
var favoriteColors: Set = ["红色", "绿色", "蓝色"]
favoriteColors.insert("黄色")
print(favoriteColors)
4. 删除元素
var favoriteColors: Set = ["红色", "绿色", "蓝色"]
// 删除一个元素
if let removeGreen = favoriteColors.remove("绿色") {
print("我已经不喜欢\(removeGreen)了")
} else {
print("我从来没喜欢过这个颜色")
}
// 删除所有元素
favoriteColors.removeAll()
print(favoriteColors)
5. 包含元素
let favoriteColors: Set = ["红色", "绿色", "蓝色"]
// 检查是否包含某元素
if favoriteColors.contains("红色") {
print("Yes")
} else {
print("No")
}
6. 集合之间的操作
(1) intersection(_:):根据两个集合中都包含的值创建一个新的集合
let a: Set<Int> = [1, 2, 3, 4, 5]
let b: Set<Int> = [4, 5, 6, 7, 8]
let c = a.intersection(b).sorted()
print(c)
(2) symmetricDifference(_:):根据包含于单个 Set 且不同时包含于两个 Set 中的值创建一个新的 Set
let a: Set<Int> = [1, 2, 3, 4, 5]
let b: Set<Int> = [4, 5, 6, 7, 8]
let c = a.symmetricDifference(b).sorted()
print(c)
(3) union(_:):根据两个 Set 包含的所有值创建一个新的 Set
let a: Set<Int> = [1, 2, 3, 4, 5]
let b: Set<Int> = [4, 5, 6, 7, 8]
let c = a.union(b).sorted()
print(c)
(4) subtracting(_:):根据 a 包含但 b 不包含的值创建一个新的 Set
let a: Set<Int> = [1, 2, 3, 4, 5]
let b: Set<Int> = [4, 5, 6, 7, 8]
let c = a.subtracting(b).sorted
print(c)
7. 集合之间的关系
(1) ==:判断两个 Set 的值是否全部相同
let a: Set<Int> = [1, 2]
let b: Set<Int> = [1, 2]
print("a 和 b 相等", a == b)
(2) isSubset(of_:):判断一个 Set 中的值是否都被包含在另外一个 Set 中
let a: Set = [1, 2, 3, 4, 5]
let b: Set = [1, 2]
print("b 是 a 的子集", b.isSubset(of: a))
(3) isSuperset(of_:):判断一个 Set 中是否包含另一个 Set 中所有的值
let a: Set = [1, 2, 3, 4, 5]
let b: Set = [1, 2]
print("a 是 b 的父集", a.isSuperset(of: b))
(4) isStrictSubset(of_:):判断一个 Set 是否是另外一个 Set 的子集合,并且两个 Set 并不相等
let a: Set = [1, 2, 3, 4, 5]
let b: Set = [1, 2, 3, 4, 3]
print("b 是 a 的子集", b.isStrictSubset(of: a))
(5) isStrictSuperset(of_:):判断一个 Set 是否是另外一个 Set 的父集合,并且两个 Set 并不相等
let a: Set = [1, 2, 3, 4, 5]
let b: Set = [1, 2, 3, 4, 3]
print("a 是 b 的父集", b.isStrictSubset(of: a))
(6) isDisjoint(with_:):判断两个 Set 是否没有交集
let a: Set = [1, 2]
let b: Set = [4, 5, 6, 7, 8]
print("a 和 b 没有交集", a.isDisjoint(with: b))
字典
dictionary:用来存储多个相同类型的值的容器。
- 每个值(value)都关联唯一的键(key);
- 键作为字典中的这个值数据的标识符;
- 字典中的数据项并没有具体顺序。
创建字典
1. 创建一个空字典
var namesOfIntegers = [Int: String]()
namesOfIntegers[16] = "sixteen"
if namesOfIntegers.isEmpty {
print("The namesOfIntegers is empty.")
}
// 代码上下文中已经提供类型信息,可以通过一个空字典字面量来创建一个空字典
namesOfIntegers = [:]
2. 用字典字面量创建字典
(1) let 常量名: Dictionary<数据类型, 数据类型> = [key1: value1, key2: value2, key3: value3, ...]
let airports: Dictionary<String, String> = ["TYO": "Tokyo", "DUB": "Dublin"]
(2) let 常量名: Dictionary = [key1: value1, key2: value2, key3: value3, ...]
let airports: Dictionary = ["TYO": "Tokyo", "DUB": "Dublin"]
- 常见操作
1. 获取字典的长度
let airports: Dictionary = ["TYO": "Tokyo", "DUB": "Dublin"]
let count = airports.count
print(count)
2. 遍历字典
(1) 以元组形式获取到 key 和 value
let airports: Dictionary = ["TYO": "Tokyo", "DUB": "Dublin", "LHR": "London"]
for (key, value) in airports {
print("key = \(key), value = \(value)")
}
(2) 只获取到 key
let airports: Dictionary = ["TYO": "Tokyo", "DUB": "Dublin", "LHR": "London"]
for key in airports.keys.sorted {
print("key = \(key)")
}
(3) 只获取到 value
let airports: Dictionary = ["TYO": "Tokyo", "DUB": "Dublin", "LHR": "London"]
for value in airports.values.sorted {
print("value = \(value)")
}
3. 字典之间的操作
var dict: [String: Any] = ["name": "小花", "age": 18]
let dict1 = ["title": "老大 ", "name": "小草"]
for (k, v) in dict1 {
dict[k] = v
}
print(dict)
4. 使用下标语法检索特定键对应的值
let airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
if let airportName = airports["DUB"] {
print("The name of the airport is \(airportName).")
} else {
print("That airport is not in the airports dictionary.")
}
5. 添加新的数据项和更新已有的数据项
(1) 使用下标语法
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// 添加新的数据项
airports["LHR"] = "London"
// 更新已有的数据项
airports["LHR"] = "London Heathrow"
(2) 使用 updateValue(_:forKey:) 方法
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
print("The old value for DUB was \(oldValue)")
} else {
print("之前不存在对应键")
}
print(airports)
6. 删除已有的数据项
(1) 使用下标语法
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
airports["APL"] = "Apple Internation"
// 删除已有的数据项
airports["APL"] = nil
print(airports)
(2) 使用 removeValue(forKey:) 方法
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
if let removeValue = airports.removeValue(forKey: "DUB") {
print("The removeValue is \(removeValue).")
} else {
print("The airports dictionary does not contain a value for DUB")
}
print(airports)
枚举
应用场景:为一系列相关联的值定义了一个公共的组类型,同时可以在类型安全的情况下去使用这些值
语法格式
enum 枚举类型名称 : 数据类型 {
// 枚举定义放在这里
}
示例代码:
enum CompassPoint {
case north // 北
case south // 南
case east // 东
case west // 西
}
enum WeekDays {
case monday, tuesday, wednesday, thursday, friday
}
- 访问
(1) 枚举类型名.成员值
示例代码 1:
enum WeekDays : Int {
case monday, tuesday, wednessday, thursday, friday
}
var day = WeekDays.friday
(2) .成员值:Swift 能够根据上下文环境推断出变量的数据类型
示例代码 2:
enum WeekDays : Int {
case monday, tuesday, wednessday, thursday, friday
}
var day = WeekDays.friday
day = .monday
(3) 成员值多选
示例代码 3:
let nameLabel = UILabel(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
nameLabel.addObserver(self, forKeyPath: "text", options: [.old, .new], context: nil)
- 赋值和取值
赋值规则:
1. Swift 的枚举成员在被创建时不会被赋予一个默认的整数值;
这些成员值本身就是完备的值;
成员值的数据类型是已经明确定义好的枚举类型。
2. 必须在枚举类型名称后面明确说明具体的数据类型;
数据类型可以是Int、Double、Character、String
3. 不必给枚举类型中的每个成员都赋值
示例代码:
enum Movement : Int {
case left = 0
case right
case top
case bottom
}
取值规则:
1. 可以通过 rawValue 属性读取枚举的原始值
2. 不同情况下的取值
(1) 枚举具体数据类型为 Int 和 Double
示例代码 1:
enum Movement: Int {
case left
case right
case top
case bottom
}
// left.rawValue = 0, 后面成员值的原始值自增长
let aMovement = Movement.left.rawValue
print(aMovement)
print(Movement.right.rawValue)
示例代码 2:
enum Movement: Double {
case left = 1
case right = 3
case top
case bottom = 7
}
// 后项 default equal to 比前项 + 1
let aMovement = Movement.left.rawValue
print(aMovement)
print(Movement.top.rawValue)
(2) 枚举具体数据类型为 String
示例代码 3:
enum Movement: String {
case left
case right
case top
case bottom
}
// left.rawValue = "left", 每一项成员值的原始值数据类型都为 String
let aMovement = Movement.left.rawValue
print(aMovement)
print(Movement.right.rawValue)
示例代码 4:
enum Movement: String {
case left = "please"
case right = "come"
case top
case bottom = "home"
}
let aMovement = Movement.left.rawValue
print(aMovement)
print(Movement.top.rawValue)
(3) 根据 rawValue 来创建一个枚举实例
示例代码:
enum Movement: Int {
case Left = 0
case Right = 1
case Top = 2
case Bottom = 3
}
// 创建一个movement.Right 用例,其raw value值为1, 返回值为可选类型
let rightMovement = Movement(rawValue: 1)
print(rightMovement!.rawValue)
- 关联值:将额外信息附加到enum case中的一种极好的方式
示例代码:
enum Barcode {
case upc(numb1: Int, numb2: Int, numb3: Int, numb4: Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(numb1: 8, numb2: 85909, numb3: 51226, numb4: 3)
// 模式匹配,访问关联值
if case var Barcode.upc(numb1, numb2, numb3, numb4) = productBarcode {
print("\(numb1), \(numb2), \(numb3), \(numb4)")
}
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
// 关联值可以被提取出来作为 switch 语句的一部分
switch productBarcode {
// 在 case 分支代码中提取每个关联值作为一个常量或者变量来使用
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case .qrCode(let productCode):
print("QR code: \(productCode).")
}
switch productBarcode {
// 为了简洁,可以只在成员名称前标注一个 let 或者 var
case let .upc(numberSystem, manufacturer, product, check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode):
print("QR code: \(productCode).")
}
类和结构体
- 类:将不同类型的数据和与这些数据的相关操作封装在一起的集合体。
1. 使用 class 定义一个类
class 类名 {
// 在这里定义类的内容
}
示例代码:
class Student {
var number: Int = 0
var name: String = ""
var height: Int = 0
var weight: Int = 0
func demo() {
print("Student")
}
}
2. 类的实例和访问
class Student {
var name: String = ""
var age: Int = 0
}
let stu = Student()
stu.name = "小明"
stu.age = 18
* 使用构造器语法来生成新的实例,构造器语法的最简单形式是在类的类型名称后跟随一对空括号,如
Student();
** 通过这种方式所创建的类,其属性都必须有初始值,并且属性会被初始化为默认值;
*** 通过使用点语法,可以访问实例的属性,其语法规则是,实例名称后面紧跟属性名,两者通过点号连接;
**** Swift 允许直接设置结构体属性的子属性。
- 结构体:是一种轻量级的类,可以在自身中定义属性和方法。
结构体都有一个自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性
1. 所有属性都有默认值,直接使用 () 来构造一个结构体实例
struct Person {
var name: String = "张三"
var age: Int = 20
}
let per = Person()
print("姓名: \(per.name) --- 年龄: \(per.age)")
2. 有一部分属性没有设置默认值,那么必须使用成员逐一构造器来构造一个结构体实例
struct Student {
var name: String
var age: Int
}
let stu = Student(name: "秦子阳", age: "18")
print(姓名: \(stu.name) --- 年龄: \(stu.age))
3. 在结构体中可以定义方法,并且可以访问成员属性
struct Teacher {
var name: String
var age: Int
var knowledge: String
func teachStudent() -> String {
return knowledge
}
}
let teacherOne = Teacher(name: "David", age: 35, knowledge: "English")
print(teacherOne.teachStudent())
let teacherTwo = Teacher(name: "LiLei", age: 25, knowledge: "Chinese")
print(teacherTwo.teachStudent())
- 类型问题
1. 值类型:被赋予给一个常量、变量或者传递给一个函数的时候,其值会被拷贝。
(1) 在 Swift 中,除了类类型以外,其余的一切数据类型都是值类型;
struct StudentInfo {
var name: String
var age: Int
funcshowStudentInfo() -> Void {
print("姓名: \(name) --- 年龄: \(age)")
}
}
// 实例化 StudentInfro 结构体
var stu1 = StudentInfo(name: "张三", age: 17)
let stu2 = stu1
stu1.showStudentInfo()
stu2.showStudentInfo()
stu1.name = "李四"
stu1.showStudentInfo()
stu2.showStudentInfo()
(2) 所有值类型数据在底层都是以结构体的形式所实现。
2. 引用类型:被赋予给一个常量、变量或者传递到一个函数时,其值不会被拷贝;引用的是已存在的实例本身。
(1) 常量和变量只是引用实例,并不"存储"实例,所以可以通过常量和变量改变实例的属性;
class VideoMode {
var interlaced = false
var frameRate = 0.0
var name: String?
}
let tenEighty = VideoMode()
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
(2) 恒等运算符:判断两个常量或者变量是否引用同一个类实例。
- 类和结构体对比
1. 共同点:
(1) 定义属性用于存储值;
(2) 定义方法用于提供功能;
(3) 定义下标操作使得可以通过下标语来访问实例所包含的值;
(4) 定义构造器用于生成初始化值;
(5) 通过扩展以增加默认实现的功能;
(6) 实现协议以提供某种标准功能。
2. 不同点:
(1) 继承允许一个类继承另一个类的特征;
(2) 类型转换允许在运行时检查和解释一个类实例的类型;
(3) 析构器允许一个类实例释放任何其所被分配的资源;
(4) 引用计数允许对一个类的多次引用。
- 类和结构体的选择
当符合一条或者多条以下条件,请考虑构建结构体:
1. 该数据结构的主要目的是用来封装少量相关简单数据值;
2. 有理由预计该数据结构的实例在被赋值或者传递时,封装的数据将会被拷贝而不是被引用;
3. 该数据结构中存储的值类型属性,也应该被拷贝,而不是被引用;
4. 该数据结构不需要去继承另一个既有类型的属性或者行为。