1. Swift中定义常量和变量
1.1 声明常量和变量
1.使用关键字 let 来声明常量,常量声明之后就不能再修改了。
2.使用关键字 var 来声明变量。
let maxCount = 10
var currentCount = 0
maxCount = 9 //这句代码会报错,let声明的常量不能被修改
currentCount = 1
在OC里面,没有特殊的说明,我们声明的都是变量,要在OC里面声明常量,我们一般使用
1.宏定义
2.const修饰词
可以在一行中声明多个变量或常量,用逗号分隔
var x=0, y=0, z=0
1.2 类型标注
1.在声明一个变量或常量的时候提供类型标注,来明确变量或常量能够存储值的类型
2.添加类型标注的方法是在变量或常量的名字后边加一个冒号,再跟一个空格(空格必须的),最后加上要使用的类型名称
3.可以在一行中定义多个相关的变量为相同的类型,用逗号分隔,只要在最后的变量名字后边加上类型标注
var str: String
str = "hello"
str = 10 //这句代码会报错,声明类型是 String,不能赋数字类型
var str1, str2 str3: String
str1 = "111"
str2 = "222"
str3 = "333"
1.3 变量和常量的命名
1.常量和变量的名字几乎可以使用任何字符,甚至包括Unicode字符
2.常量和变量的名字不能包含 空白字符、数学符号、箭头、保留的Unicode码位、连线和制表符。也不能以数字开头,尽管数字几乎可以使用在名字其他的任何地方。
swift虽然命名可以使用的字符很多,但是大家平常写代码最好还是规范命名,尽量做到 看其名,知其意。正确并形象地给变量命名,不仅可以增加程序的可读性,也是程序员编程风格的一种反映
1.4 打印常量和变量
1.print方法
2.字符串插值方法
let str = "world"
print("hello, world")
print("hello, \(str)")
2. Swift中的数值类型
2.1 整数
1.Swift提供了8、16、32、64位编码的有符号和无符号整数
2.命名方式:例如8位无符号整数的类型是Uint8,32位有符号整数的类型是Int32
3.通过 min 和 max 属性来访问每个整数类型的最小值和最大值
4.Swift提供了一个额外的整数类型:Int,它拥有与当前平台的原生字相同的长度,假如 当前平台是32位的,Int 就是32位的,假如当前平台是64位的,Int 就是64位的
5.同时Swift也提供 Uint 类型,来表示平台长度相关的无符号整数
6.建议在用到整数的地方都使用 Int
2.2 浮点类型
1.Double:64位浮点数,至少有15位数字的精度
2.Float:32位浮点数,至少有6位数字的精度
3.在两种类型都可以的情况下,推荐使用 Double 类型
2.3 Bool
1.Bool:true 和 false
2.Swift 的类型安全机制会阻止你用一个非布尔量的值替换掉 Bool
//编译错误
let i = 1
if i {
print(i)
}
//正确写法
let i = 1
if i==1 {
print(i)
}
2.4 类型别名
1.类型别名是一个为已存在的类型定义的一个可选择的名字
2.可以用关键字 typealias 定义一个类型的别名
typealias AudioSample = UInt8
let sample: AudioSample = 32
3. Swift的 Tuple(元组) 类型
3.1 元组定义
1.元组把多个值合并成单一的复合型的值,多个值统一放在小括号里面,之间用逗号分隔
2.元组内的值可以是任何类型,而且可以不必是同一类型
let error = (404, "没找到网络地址")
print(error.0) //404
print(error.1) //没找到网络地址
3.元组中的每一个元素可以指定对应的元素名称
4.如果没有指定名称的元素也可以使用下标的方式来引用
let error = (errCode: 404, errMsg: "没找到网络地址")
print(error.errCode) //404
print(error.errMsg) //没找到网络地址
3.2 元组修改
1.用 var 定义的元组是可变元组,let 定义的就是不可变元组
2.不管是可变还是不可变元组,元组在创建后就不能增加和删除元素
3.可以对可变元组的元素进行修改,但是不能改变其类型
4.any 类型可以改为任何类型
var error: (Any, String) = (404, "没找到网络地址")
error.0 = 500
print(error) //(500, "没找到网络地址")
error.0 = "abc"
error.1 = "未知错误"
print(error) //("abc", "未知错误")
3.3 元组分解
1.可以将一个元组的内容分解成单独的常量或变量
2.如果只需要使用其中的一部分数据,不需要的数据可以用下划线(_)代替
let error = (404, "没找到网络地址")
let (_, errMsg) = error
print(errMsg) //没找到网络地址
3.4 作为函数返回值
1.使用元组为函数返回多个值
2.返回值的元组可以在函数的返回类型部分被命名
func requestData(url: String) -> (errCode: Int, errMsg: String) {
return (404, "没找到网络地址");
}
4. Swift字符串
4.1 初始化字符串
1.字面量--被双引号("")包裹的固定顺序文本字符
2.初始化器语法
3.isEmpty 检查是否为空串
var emptyStr = ""
var emptyStr2 = String()
if emptyStr.isEmpty {
print("emptyStr is empty")
}
var someStr = "some string"
var someStr2 = String("some string")
if !someStr2.isEmpty {
print(someStr2);
}
4.多行字面量
多行字符串字面量是用三个双引号引起来的一系列字符;把所有行包括在引号内,开始和结束默认不会有换行符;当你的代码中在多行字符串字面量里包含了换行,那个换行符同样会成为字符串里的值,如果你想要使用换行符来让你的代码易读,却不想让换行符成为字符串的值,那就在那些行的末尾使用反斜杠(\)
let multiLineStr = """
Q: What's your name?
A: my name is joke.
Q: What's your job?
A: I'm an iOS developer.
Q: You have a very good job.
"""
print(multiLineStr)
4.2 字符串的常见操作
1.let 指定的字符串是不可以修改的,var 指定的字符串可以修改,可以使用“+”来拼接字符串
let letString = "hello"
letString += " world!" //编译报错
var varString = "hello"
varString += " world!"
print(varString) //hello world!
2.字符串是值类型,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
3.操作字符,可以通过 for-in 循环遍历 String 中的每一个独立的 Character,String 值可以通过传入 Character 数组来构造
for character in "I'm an ios developer" {
print(character)
}
let iosCharacter: [Character] = ["i", "O", "S"]
let iosString = String(iosCharacter)
print(iosString) //iOS
4.字符串拼接
使用加运算符(+)创建新的字符串
使用加赋值符号(+=)在已经存在的 String 值末尾追加一个 String 值
使用 String 类型的 append() 方法来可以给一个 String 变量的末尾追加 Character 值
var str = "hello"
var newStr = str + " oc"
print(newStr) //hello oc
str += " swift"
print(str) //hello swift
str.append(" world") //hello swift world
print(str)
5.字符串插值,是一种字符串字面量构造新 String 值的方法,混合了 常量、变量、字面量、表达式;每一个插入到字符串字面量的元素都要被一对圆括号包裹,然后使用反斜杠前缀;字符串插值类似于 NSString 的 stringWithFormat 方法
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
print(message) //3 times 2.5 is 7.5
6.字符串索引
每一个 String 值都有相关的索引类型,String.Index,是个结构体类型, 它相当于每个 Character 在字符串中的位置;startIndex 属性来访问 String 中第一个 Character 的位置,endIndex 属性就是 String 中最后一个字符后的位置;如果 String 为空,则 startIndex 与 endIndex 相等
let str = "hello world!"
print(str[str.startIndex]) //h
print(str[0]) //编译报错
使用 index(before:) 和 index(after:) 方法来访问给定索引的前后
要访问给定索引更远的索引,你可以使用 index(_:offsetBy:)
let str = "hi world"
let index1 = str.index(after: str.startIndex)
let index2 = str.index(before: str.endIndex)
let index3 = str.index(str.startIndex, offsetBy: 3)
print(str[index1]) //i
print(str[index2]) //d
print(str[index3]) //w
7.字符串插入
插入字符,使用 insert(_:at:) 方法
插入字符串,使用 insert(contentsOf:at:) 方法
var welcome1 = "hello"
welcome1.insert("!", at: welcome1.endIndex)
print(welcome1) //hello!
var welcome2 = "hello"
welcome2.insert(contentsOf: " there", at: welcome2.endIndex)
print(welcome2) //hello there
8.字符串删除
移除字符,使用 remove(at:) 方法
移除一小段特定范围的字符串,使用 removeSubrange(_:) 方法
var welcome1 = "hello there!"
welcome1.remove(at: welcome1.index(before: welcome1.endIndex))
print(welcome1) //hello there
var welcome2 = "hello there!"
let range = welcome2.index(welcome2.endIndex, offsetBy: -5) ..< welcome2.endIndex
welcome2.removeSubrange(range)
print(welcome2) //hello t
9.子字符串
使用下标或者类似 prefix(_:) 的方法得到的子字符串是 Substring 类型
Substring 拥有 String 的大部分方法
Substring 可以转成 String 类型
let welcome = "hello,there!"
let index = welcome.firstIndex(of: ",") ?? welcome.endIndex
let subString = welcome[..<index]
print(subString) //hello
let newString = String(subString)
print(newString) //hello
之所以会搞一个 Substring 类型,很大程度上是为了性能而考虑的。
子字符串重用一部分原字符串的内存
修改字符串或者子字符串之前都不需要花费拷贝内存的代价
String 和 Substring 都遵循 StringProtocol 协议,也就是说它基本上能很方便地兼容所有接受 StringProtocol 值的字符串操作函数
10.字符串比较
字符串和字符串相等性(==和!=)
前缀相等性 hasPrefix(:)
后缀相等性 hasSuffix(:)
var welcome1 = "hello, world"
var welcome2 = "hello, world"
var welcome3 = "hello"
print(welcome1 == welcome2) //true
print(welcome1 == welcome3) //false
print(welcome2.hasPrefix("hello")) //true
print(welcome3.hasPrefix("hello")) //true
5. Optional(可选)类型
5.1 Optional 定义
1.通过在变量类型后面加 ? 表示:
这里有一个值,他等于 x
或者
这里根本没有值
2.你可以通过给可选变量赋值一个 nil 来将之设置为没有值
在 OC 中 nil 是一个指向不存在对象的指针
在 Swift 中,nil 不是指针,他是值缺失的一种特殊类型,任何类型的可选项都可以设置成 nil 而不仅仅是对象类型
3.可选项是没法直接使用的,需要用 ! 展开之后才能使用,使用 ! 来获取一个不存在的可选值会导致运行错误,在使用 ! 强制展开之前必须确保可选项中包含一个非 nil 的值
var str: String = nil; //编译报错 swift中 不是可选变量 不能赋值为nil
var str1: String? = nil
var str2: String? = "abc"
let count = str.count //编译报错 可选值不能直接使用
var str3: String? = "abc"
if str3 != nil {
let count = str3!.count //通过 ! 展开可选值 使用
print(count)// 3
}
5.2 Optional 绑定
1.可以使用可选项绑定来判断可选项是否包含值,如果包含就把值赋给一个临时的常量或者变量
2.可选绑定可以与 if 和 while 的语句使用来检查可选项内部的值,并赋值给一个变量或常量
3.同一个 if 语句中包含多个可选项绑定,用逗号分隔即可。如果任一可选绑定结果是 nil 或者布尔值为 false,那个整个 if 判断会被看作 false
var str: String? = "abc"
if let actualStr = str {
let count = actualStr.count
print(count)
}
5.2 Optional 隐式展开
1.有些可选项一旦被设定值之后,就会一直拥有值,在这种情况下,就可以去掉检查的需求,也不必每次访问的时候都进行展开
2.通过在声明的类型后边添加一个叹号(String!)而非问号(String?)来书写隐式展开可选项
3.隐式展开可选项主要被用在 Swift 类的初始化过程中
var str: String! = "abc"
let count = str.count
print(count) //3
5.3 Optional 可选链
1.可选项后面加问号来使用
2.可选链调用的结果一定是一个可选值
var str: String? = "abc"
let strCount = str?.count //使用可选链,可选链语句返回的值也是个可选值,所以 strCount 也是个可选值
if strCount != nil {
let lastIndex = strCount! - 1
print(lastIndex) //2
}
5.4 Optional 实现原理
1.Optional 其实是标准库里的一个 enum 类型
2.Optional 是用标准库实现语言特性的典型,下面是从标准库拷贝来的Optional源码
@frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral {
/// The absence of a value.
///
/// In code, the absence of a value is typically written using the `nil`
/// literal rather than the explicit `.none` enumeration case.
case none
/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
/// Creates an instance that stores the given value.
public init(_ some: Wrapped)
/// Evaluates the given closure when this `Optional` instance is not `nil`,
/// passing the unwrapped value as a parameter.
Optional.none 就是 nil
Optional.some 则包装了实际的值
//下面用 Optional 枚举来定义一个可选值
var str: Optional<String> = "abc" //和语句 var str: String? = "abc" 一样
if let actualStr = str {
let count = actualStr.count
print(count) //3
}
- Optional 有个泛型属性 unsafelyUnwrapped,用来获取可选项实际的值。unsafelyUnwrapped 在标准库的说明如下。
/// The wrapped value of this instance, unwrapped without checking whether
/// the instance is `nil`.
///
/// The `unsafelyUnwrapped` property provides the same value as the forced
/// unwrap operator (postfix `!`). However, in optimized builds (`-O`), no
/// check is performed to ensure that the current instance actually has a
/// value. Accessing this property in the case of a `nil` value is a serious
/// programming error and could lead to undefined behavior or a runtime
/// error.
///
/// In debug builds (`-Onone`), the `unsafelyUnwrapped` property has the same
/// behavior as using the postfix `!` operator and triggers a runtime error
/// if the instance is `nil`.
///
/// The `unsafelyUnwrapped` property is recommended over calling the
/// `unsafeBitCast(_:)` function because the property is more restrictive
/// and because accessing the property still performs checking in debug
/// builds.
///
/// - Warning: This property trades safety for performance. Use
/// `unsafelyUnwrapped` only when you are confident that this instance
/// will never be equal to `nil` and only after you've tried using the
/// postfix `!` operator.
@inlinable public var unsafelyUnwrapped: Wrapped { get }
理论上我们可以直接调用 unsafelyUnwrapped 获取可选项的值
var str: String? = "abc"
let count = str.unsafelyUnwrapped.count
print(count) //3