前言
废话不多说,直接进入正题
Swift基础数据类型
常量和变量
let 来声明常量 ,只能赋值一次,它的值不要求在编译时期确定,但使用之前必须赋值一次
var 来声明变量
var x = 1, y = 2, z = 3
类型标注,来明确变量或常量能够储存值的类型
var name : String = "Wang"
标识符
常量和变量的名字几乎可以使用任何字符,甚至包括 Unicode 字符
常量和变量的名字不能包含空白字符、数学符号、箭头、保留的(或者无效的) Unicode 码位、连线和制表符。也不能以数字开头,尽管数字几乎可以使用在名字其他的任何地方
let π = 3.1415
let = "牛马"
print("打印\()")
基本数据类型
整数
Swift 提供了 8,16,32 和 64 位编码的有符号和无符号整数
命名方式:例如 8 位无符号整型 UInt8 ,32 位有符号整型 Int32
可通过 min/max 来访问最小/大值
print(uint8.min)
print(uint8.max)
输出分别是0和255
Int 、UInt 拥有与当前平台的原生字相同的长度,推荐使用
浮点数
Double:64 位浮点数,至少有 15 位数字的精度
Float:32 位浮点数,至少有 6 位数字的精度
在两种类型都可以的情况下,推荐使用 Double 类型。
类型 | 大小(字节数) | 区间值 |
---|---|---|
Int8 | 1字节 | -128 到 127 |
UInt8 | 1字节 | 0 到 255 |
Inte32 | 4字节 | -2147483648 到 2147483647 |
UInt32 | 4字节 | 0 到 4294967295 |
Inty64 | 8字节 | -9223372036854775808 到 9223372036854775807 |
UInt64 | 8字节 | 0 到 18446744073709551615 |
Float | 4字节 | 1.2E-38 到 3.4E+38 (~6 digits) |
Double | 8字节 | 2.3E-308 到 1.7E+308 (~15 digits) |
Bool
Swift 是类型安全的 ,判断语句中不允许传入非布尔值正确代码:
let i = 1
if i == 1 {
print(i)
}
类型别名
为已存在类型定义一个更具有表达性的名字
typealias SoundVolume = UInt8 // 音量值
let volume : SoundVolume = 5
字面量
简洁明了的指出自己的类型并且能为变量赋值的值
// 布尔
let bool = true //取反是false
// 整数
let intDecimal = 17 //十进制
let intBinary = 0b10001 //二进制
let intOctal = 0o21 //八进制
let intHexadecimal = 0x11 //十六进制
// 浮点数
let doubleDecimal = 125.0 //十进制,等价于1.25e2,0.0125等价于1.25e-2
let doubleHexadecimal1 = 0xFp2 //十六进制,意味着15x2^2,相当于十进制的60.0
let doubleHexadecimal2 = 0xFp-2 //十六进制,意味着15x2^-2,相当于十进制的3.75
// 字符串
let string = "字符串"
// 字符(可存储ASCII字符、Unicode字符)
let character: Character = ""
// 数组
let array = [1, 3, 5, 7, 9]
// 字典
let dictionary = ["height" : 180, "age" : 18]
整数和浮点数可以添加额外的零或者添加下划线_来增强可读性
let num = 100_0000
let num2 = 1_000_000.000_000_1
let num3: Double = 000123.456
元组
元组把多个值合并成单一的复合型的值
元组内的值可以是任何类型,而且可以不必是同一类型
元组中的每一个元素可以指定对应的元素名称
如果没有指定名称的元素也可以使用下标的方式来引用
let error = (errorCode: 404, "错误")
print(error.errorCode)
print(error.1)
// 输出:404 错误
元组修改
var 定义可变元组,let 定义不可变元组
不管是可变还是不可变元组,元组在创建后就不能增加和删除元素
可以对可变元组的元素进行修改,但是不能改变其类型
var error = (errorCode: 404, errorMsg: "错误")
error.errorCode = 2
// error.errorCode = "2" 报错:'Cannot assign value of type 'String' to type 'Int''
any 类型可以改为任何类型
var error:(errorCode: Any, errorMsg: String) = (errorCode: 404, errorMsg: "错误")
error.errorCode = 2
error.errorCode = "2"
元组拆解
将一个元组的内容分解成单独的常量或变量
let error = (404, "错误")
let (errorCode, errorMsg) = error
print(errorCode)
print(errorMsg)
如果只需要使用其中的一部分数据,不需要的数据可以用下滑线 _ 代替
let error = (404, "错误")
let (errorCode, _) = error
print(errorCode)
元组作为函数返回值
使用元组为函数返回多个值
func request(url: String) -> (errorCode: Int, errorMsg: String) {
return (404, "错误")
}
Optional
在类型名称后面加个问号?来定义一个可选项
可选项是对其他类型的一层包装,可以将它理解为一个盒子
- 如果为nil,那么它是个空盒子
- 如果不为nil,那么盒子里装的是:被包装类型的数据
- 在 Swift 中,nil 不是指针,而是值缺失的一种特殊类型,任何类型的可选项都可以设置成 nil 而不仅仅是对象类型
var age: Int? //默认就是nil
age = 10
age = nil
强制解包
如果要从可选项中取出被包装的数据,需要使用感叹号!进行强制解包
var age: Int? = 10
let ageInt: Int = age!
ageInt += 10
对值为nil的可选项进行强制解包,会产生运行时错误
判断可选项是否包含值
let num = Int("123")
if num != nil {
print("字符串转换整数成功:\(num!)")
}
var str: String? = "abc"
if str != nil {
print(str!)
}
可选项绑定
可以使用可选项绑定来判断可选项是否包含值
如果包含就自动解包,把值赋给一个临时常量(let)或者变量(var),并返回true,否则返回false
var str: String? = "abc"
if let number = Int("123"), let tempStr = str {
print(tempStr,number)
}
else {
print("nil")
}
隐式解包
有些可选项一旦被设定值之后,就会一直拥有值,在这种情况下,就可以去掉检查的需求, 也不必每次访问的时候都进行解包
在声明的类型后边添加一个叹号! 而非问号?
var string: String! = "efg"
if let tempString = string {
print(tempString)
}
多重可选项
可选项(盒子)后面加问号?
如果可选项不为nil,返回一个可选项,否则返回nil
var str: String? = "efg"
let count = str?.count
if count != nil {
let lastIndex = count! - 1
print(lastIndex)
}
var num1: Int? = 10
var num2: Int?? = num1
var num3: Int?? = 10
print(num2 == num3) //true
可选项打印
可选项在字符串插值或者直接打印时,编译器会发出警告至少有3种方法消除警告
var age: Int? = 10
print("年龄:\(age!)")
// 年龄:10
print("年龄:\(String(describing: age))")
// 年龄:Optional(10)
print("年龄:\(age ?? 0)")
// 年龄:10
字符串
初始化空串
- 字面量
var emptyString = ""
- 初始化器语法
var emptyString = String()
// isEmpty检查是否为空字符串
if emptyString.isEmpty {
print("empty")
}
多行字面量
- 如果你想要使用换行符来让你的代码易读,却不想让换行符成为字符串的值,那就在那些行的末尾使用反斜杠\
- 如果你在某行的空格超过了结束的双引号( """ ),那么这些空格会被包含
let mutableStr = """
当你的代码中在多行字符串字面量里包含了换行,\
那个换行符同样会成为字符串里的值。
如果你想要使用换行符来让你的代码易读,
却不想让换行符成为字符串的值,
那就在那些行的末尾使用反斜杠
"""
print(mutableStr)
字符串里的特殊字符
- 转义特殊字符 \0 (空字符), \\ (反斜杠), \t (水平制表符), \n (换行符), \r(回车符), \" (双引号) 以及\ ' (单引号)
let str = "老实说:\"哈哈。\"\t\'呵呵\'"
- 任意的 Unicode 标量,写作 \u{n},里边的 n 是一个 1-8 位的16 进制数字,其值是合法 Unicode 值
let uniStr = "\u{24}" // $
let uniStr2 = "\u{2665}" // ♥
let uniStr3 = "\u{1F496}"//
- 可以在多行字符串字面量中包含双引号( " )而不需转义。要在多行字符串中包含文本 """ ,转义至 少一个双引号
let mutableStr = """
可以在多行字符串字面量中包含双引号( " )而不需转义。要在多行字符串中包含文本 "\"" ,转义至少一个双引号
"""
扩展字符串分隔符
把字符串放在双引号( " )内并由井号( # )包裹
在字符串字面量中放置扩展分隔符来让其中包含的特殊字符不生效
let str = "Line 1\nLine 2" //正常换行
let str2 = #"Line 1\nLine 2"# //Line 1\nLine 2 换行失效
如果字符串里有" # 需要显示则首尾需要两个 ##
如果需要字符串中某个特殊符号的效果,使用匹配你包裹的井号数量的井号并在前面写转义符号 \
let str3 = ##"Line 1\#nLine 2"\nLine 3\##nLine 4"##
/* 打印结果:
Line 1\#nLine 2"\nLine 3
Line 4
*/
可变与不可变字符串
字符串是值类型
- String 值在传递给方法或者函数的时候会被复制过去
- 赋值给常量或者变量的时候也是一样
- Swift 编译器优化了字符串使用的资源,实际上拷贝只会在确实需要的时候才进行
var str: String = "abc"
var str1 = str
print(str == str1) // true
str += "def"
print(str) // abcdef
print(str1) // abc
print(str == str1) // false
Character 类型
- for-in 循环遍历 String 中的每一个独立的
- String 值可以通过传入 Character 数组来构造
let catCharacter: [Character] = ["C", "A", "T", ""]
let catWord: String = String(catCharacter)
print(catWord)
字符串拼接
var str2 = "新年" + "快乐"
print(str2) //新年快乐
str2 += "!"
print(str2) // 新年快乐!
str2.append("")
print(str2) // 新年快乐!
字符串插值
- 字符串插值是一种从混合常量、变量、字面量和表达式的字符串字面量构造新 String 值的方法
- 每一个你插入到字符串字面量的元素都要被一对圆括号()包裹,然后使用反斜杠\前缀
- 类似于 NSString 的 stringWithFormat 方法,但是更加简便,更强大
let age = 3
let desc = "\(age) 它的2.5倍是:\(Double(age) * 2.5)"
要在使用扩展分隔符的字符串中使用字符串插值,在反斜杠后使用匹配首尾井号数量的井号
print(#"它的2.5倍是:\(Double(age) * 2.5)"#) // 它的2.5倍是:\(Double(age) * 2.5)
print(#"它的2.5倍是:\#(Double(age) * 2.5)"#) // 它的2.5倍是:7.5
字符串索引
- 每一个 String 值都有相关的索引类型, String.Index,它相当于每个 Character在字符串中的位置
- 使用 index(before:) 和 index(after:) 方法来访问给定索引的前后
let str: String = "abcdefg"
print(str.startIndex) // Index(_rawBits: 1)
print(str[str.startIndex]) // a
print(str.endIndex) // Index(_rawBits: 458753)
print(str[str.index(before: str.endIndex)]) // g
print(str[str.index(after: str.startIndex)]) //b
// 如果 String 为空,则 startIndex 与 endIndex 相等
let str2: String = ""
print(str2.startIndex == str2.endIndex) // true
- 要访问给定索引更远的索引,你可以使用 index(_:offsetBy:)
let str: String = "abcdefg"
let index = str.index(str.startIndex, offsetBy: 5)
print(str[index]) // f
let index2 = str.index(str.startIndex, offsetBy: 9) // 越界崩溃
- 使用 indices 属性来访问字符串中每个字符的索引
for index in str.indices {
print(index)
}
插入 & 删除
var welcome = "hello "
welcome.insert("!", at: welcome.endIndex) //hello !
welcome.insert(contentsOf: "word", at: welcome.index(before: welcome.endIndex)
print(welcome) // hello word!
welcome.remove(at: welcome.index(before: welcome.endIndex))
print(welcome) // hello word
let range = welcome.index(welcome.endIndex, offsetBy: -5)..
子字符串
- 使用下标或者类似 prefix(_:) 的方法得到的子字符串是 Substring 类型
- Substring 拥有 String 的大部分方法
- 子字符串重用一部分原字符串的内存
var welcome = "hello, word!"
let subStr = welcome.prefix(5)
print(subStr)
let index = welcome.index(welcome.startIndex, offsetBy: 7)
let endStr = welcome[index..
字符串比较
var welcome = "hello, word!"
var welcome1 = "hello"
print(welcome == welcome1) // false
print(welcome.hasPrefix("hello")) // true
print(welcome.hasSuffix("word!")) // true