swift特性:
- 支持泛型
- 支持元组
- 函数嵌套
- 结构体、枚举可以定义函数、属性
- set get willset didset 写在一个地方
- 属性没有成员变量
- 变量var 常量let
- 类型安全的语言,必须初始化
- 有可选类型 Int 和 Int?是两种类型,可选绑定 可选链 guard关键字
- 符号函数 + +=(str1+str2)
- 数组、字典 key/value类型相同,Any AnyObject除外
- 有区间类型 ...
- 系统自带高阶函数
- Int Double等类型 必须转换
- extension强大
- 可对协议扩展
一:声明常量、变量
1、Swift中声明变量使用var关键字,使用let声明常量
2、一旦常量定义了,就不可改变
3、这里变量名后边的 : String : Float 可以省略,编译器会通过赋值得知这个变量属于什么类型
4、常量和变量名可以包含任何字符,包括 Unicode 字符
5、变量和常量名不能以数字开头
var name: String = "xxx"
let height: Float = 1.80
二:基本数据类型
Int、Float、Double
1、Swift中增加了Int8 Int16 Int32 Int64等类型,一般使用Int就够了
- 在32位平台上,Int 和 Int32 长度相同。
- 在64位平台上,Int 和 Int64 长度相同。
2、类型转换
var xx = Double(3)
var xxx = Int(3.14)
3、Bool值,Swift中Bool是 true 和 false两个值,Swift中条件语句中是用Bool值来判断的,不像OC中的 不为0、nil就是真
let i = 1
if i {
// 这个例子不会通过编译,会报错
}
let i = 1
if i == 1 {
// 这个例子会编译成功
}
三:元组
1、元组最大的用处是当需要返回多个值的函数,试想下OC中,想返回多个值,得包装在NSArray或NSDictionary或NSString中,有了元组,直接可返回多个值
let http404Error = (404, "Not Found")
//http404Error 的类型是 (Int, String),值是 (404, "Not Found")
可以赋值:
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// 输出“The status code is 404”
print("The status message is \(statusMessage)")
// 输出“The status message is Not Found”
还可以通过下标来访问:
print("The status code is \(http404Error.0)")
// 输出“The status code is 404”
print("The status message is \(http404Error.1)")
// 输出“The status message is Not Found”
四:可选类型
1、可选类型是来处理值可能缺失的情况,或者为nil,或者有值,为可选类型,使用可选绑定或者拆包来获取值
字符串转换为Int
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber 被推测为类型 "Int?", 或者类型 "optional Int"
通过可选绑定或者强拆包来获取值
if let xx = convertedNumber {
print(xx) //打印123
}
假如你知道这个convertedNumber变量一定有值,直接使用!拆包
print(convertedNumber!)
如果声明一个可选类型且没有赋值,编译器默认会赋值nil
var surveyAnswer: String?
// surveyAnswer 被自动设置为 nil
五:可选绑定
标准可选绑定示例:意思是someOptional有值,然后赋值给临时常量constantName
if let constantName = someOptional {
statements
}
可以包含多个可选绑定或bool条件在一个if语句中:
下面两个示例是一个意思
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
// 输出“4 < 42 < 100”
if let firstNumber = Int("4") {
if let secondNumber = Int("42") {
if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
}
}
// 输出“4 < 42 < 100”
guard语句,guard语句当不满足条件时直接走大括号内逻辑,提前退出代码块,满足条件,走guard语句后边代码,guard后边必须跟着一个else从句
guard let name = nameStr, name.count > 0 else {
return
}
代码逻辑
...
...
...
六:运算符
- 算术运算符 + - * \
- % 求余
- = 赋值运算符
- 三目运算符 ?:
- 组合运算符 += -= *= =
- 比较运算符 == != > >= < <=
- 空合运算符 ?? 可选值为空时,选择默认值
- 区间运算符 (闭区间)... (半开区间)..<
- 逻辑运算符 逻辑或|| 逻辑与&& 逻辑非!
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
print("第 \(i + 1) 个人叫 \(names[i])")
}
// 第 1 个人叫 Anna
// 第 2 个人叫 Alex
// 第 3 个人叫 Brian
// 第 4 个人叫 Jack
单侧区间:
for name in names[2...] {
print(name)
}
// Brian
// Jack
for name in names[...2] {
print(name)
}
// Anna
// Alex
// Brian
半开区间
for name in names[..<2] {
print(name)
}
// Anna
// Alex
七:字符串String和字符Character
1、字符串是值类型,不同于OC的NSString对象类型
2、字面量创建字符串
let str = "some string"
3、多行串使用 """ """包裹
let name = """
li
xxx
xxx
print(name)
打印:
li
xxx
xxx
"""
4、转义字符 \0(空字符)、\(反斜线)、\t(水平制表符)、\n(换行符)、\r(回车符)、"(双引号)、'(单引号)。 5、 += 符合运算符,是运算符函数,String重载了该运算符
var name = "li"
name += " n"
let str = name + "ing"
print(str)
打印:li ning
6、遍历字符串每一个字符
for c in "Dog!🐶" {
print(c)
}
打印:
// D
// o
// g
// !
// 🐶
7、使用字符数组组成字符串
let characters: [Character] = ["c","a","t"]
let cat = String(characters)
print(cat)
8、+ 连接符
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome 现在等于 "hello there"
9、常用属性、方法:
- count
- func append(_ other: String) 末尾添加串
- func append(_ c: Character) 末尾添加字符
- func remove(at i: String.Index) -> Character
- func insert(_ newElement: Character, at i: String.Index)
- func hasPrefix(_ prefix: String) -> Bool
- func hasSuffix(_ suffix: String) -> Bool
- 等等
10、子字符串: 官方文档的一段话,比较长
就像 String,每一个 Substring 都会在内存里保存字符集。而 String 和 Substring 的区别在于性能优化上,Substring 可以重用原 String 的内存空间,或者另一个 Substring 的内存空间(String 也有同样的优化,但如果两个 String 共享内存的话,它们就会相等)。这一优化意味着你在修改 String 和 Substring 之前都不需要消耗性能去复制内存。就像前面说的那样,Substring 不适合长期存储 —— 因为它重用了原 String 的内存空间,原 String 的内存空间必须保留直到它的 Substring 不再被使用为止。
子字符串也是一种类型,可以和字符串共用内存空间来提高性能。
一张图来表示内存关系:
八:集合类型
1、Swift集合类型有Array、Dictionary、Set
2、Array是有序集合,Set是无序无重复集合,Dictionary是无序键值对
3、Swift集合是值类型,不同于OC的对象类型NSArray、NSDictionary、NSSet
4、Swift的Array被桥接到了OC的NSArray,详情请看bridge
5、创建数组
var someInts = [Int]()
someInts.append(3)
带默认值
var threeDoubles = Array(repeating: 0.0, count: 3)
使用+运算符
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
var sixDoubles = threeDoubles + anotherThreeDoubles
可以把:[String]去掉,编译器会通过上下文知道数组类型
var shoppingList: [String] = ["Eggs", "Milk"]
var shoppingList = ["Eggs", "Milk"]
数组遍历:
for item in arr {
print(item)
}
for index in 0..<arr.count {
print(i)
}
for (index,item) in arr.enumerated() {
print("\(index) -- \(item)")
}
Set:
1、Set是无序无重复的集合,其他和Array相似
2、数学 常用方法
- 使用 intersection(_:) 方法根据两个集合的交集创建一个新的集合。
- 使用 symmetricDifference(_:) 方法根据两个集合不相交的值创建一个新的集合。
- 使用 union(_:) 方法根据两个集合的所有值创建一个新的集合。
- 使用 subtracting(_:) 方法根据不在另一个集合中的值创建一个新的集合。
官网示例:
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]
字典
1、一个字典的key必须遵循Hashable协议
2、字典的key和value需是相同类型,[Int:String] key是Int类型,value是String类型
3、其他使用详情请移步官方文档
九:控制流
1、for-in
2、while
3、repeat-while 和OC的 do-while循环类似,一定走一次代码块
4、if-else
5、switch-case Swift的switch语句要遍历完所有的case情形,要不然给一个default,没有列出的case情形会走default
6、case语句不存在隐式贯穿,也就是说不需要显式的写break,执行完case中的语句会直接退出
7、case语句支持区间匹配
官网示例:
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// 输出“There are dozens of moons orbiting Saturn.”
8、case语句可以使用元组,且可以使用值绑定
官网示例:
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("\(somePoint) is at the origin")
case (_, 0):
print("\(somePoint) is on the x-axis")
case (0, _):
print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
print("\(somePoint) is inside the box")
default:
print("\(somePoint) is outside of the box")
}
// 输出“(1, 1) is inside the box”
值绑定:
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
// 输出“on the x-axis with an x value of 2”
9、case语句可以使用 where添加额外判断条件
官网示例:
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
// 输出“(1, -1) is on the line x == -y”
10、复合型case,多个可能放在一个case语句中,使用,隔开
11、使用fallthrough关键字,使走完的case语句自动走到下一个case中
官方示例:
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// 输出“The number 5 is a prime number, and also an integer.”
十:函数
- 没有返回值的函数默认返回一个Void特殊值 ,该值是一个空元组,()
- 函数代码块中单一表达式时,可以省略return,隐式返回
//有参有返
func xxx(age: Int) -> Int {
return age+1
}
//还可以把age省略,调用的地方看不到age _
func xxx(_ age: Int) -> Int {
return age+1
}
//隐式返回
func xxx(age: Int) -> Int {
age+1
}
//返回元组
func xxx(n: String,a: Int) -> (name: String,age: Int) {
return (n,a)
}
//无参无返
func xxx() -> Void {
}
//还可以把 -> Void 省略
func xxx() {
}
//带标签函数,函数内部age是参数
func xxx(label age: Int) {
}
//带有默认值参数的函数,调用方可忽略age参数
func xxx(name: String ,age: Int = 9) {
}
xxx(name: "")
//可变参数
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// 返回 3.0, 是这 5 个数的平均数。
arithmeticMean(3, 8.25, 18.75)
// 返回 10.0, 是这 3 个数的平均数。
//函数类型作为函数参数,闭包
func xxx(closure: (Int) -> Int,num: Int) -> Int {
return closure(num*2)
}
//嵌套函数 函数中声明函数
十一:闭包
1、闭包是引用类型,跟OC的block一样也是对象类型
2、闭包表达式
{ (paras) -> returntype in
代码块
}
3、下边以系统方法sorted举例:
//定义一个数组
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
//sorted接受一个 (String,String) -> Bool 参数
let a = names.sorted(by: (String, String) -> Bool)
//定义一个参数为(String,String) -> Bool函数
func back(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
//把back函数传递给sorted函数
let a = names.sorted(by: back(s1:s2:))
//1、闭包表达式代码:
let a = names.sorted { (s1: String, s2: String) -> Bool in
return s1 > s2
}
//2、闭包可以根据上下文推断类型,可以去掉对应类型
let a = names.sorted { (s1, s2) in
return s1 > s2
}
//3、参数的括号也可以忽略
let a = names.sorted { s1, s2 in
return s1 > s2
}
//4、如果是单表达式,可以隐式返回,忽略return
let a = names.sorted { s1, s2 in
s1 > s2
}
//5、参数名可以简写,$0,$1,以此类推
let a = names.sorted { $0 > $1 }
//运算符方法 String类型定义了 >运算符函数,类型也是(String,String) -> Bool,只写一个 > ,swift会自动去找系统 >符号方法
let a = names.sorted(by: >)
4、尾随闭包 尾随闭包是闭包作为函数的最后一个参数,可以写在函数圆括号外边的闭包表达式。
//文档示例:
func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函数体部分
}
// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure(closure: {
// 闭包主体部分
})
// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
// 闭包主体部分
}
举例:
//定义一个函数,函数最后一个参数是闭包函数
func xxx(num: Int,closure: (Int) -> Int) -> Int {
return closure(num)
}
//正常写法
let b = xxx(num: 2, closure: {(n: Int) -> Int in
return n*n
})
//尾随闭包写法
let a = xxx(num: 2) { (n) -> Int in
return n*n
}
//还可以简写成这样
let b = xxx(num: 7) { $0*$0 }
5、值捕获 闭包可以在其定义的地方捕获上下文的变量或者常量,当定义的变量或者常量的原作用域不存在时,在闭包内依然可以使用这些变量常量,也就是说,那些变量常量类似于copy到闭包了一份。OC的block有同样的机制,block捕获的变量不受外界影响,block内部维护变量的生命周期,不过block要加上__block修饰符。显然Swift处理了更多的东西,使用户不必有太多关心。
//模拟网络请求,当网络请求数据回来,suc,failed执行,且这两个闭包是逃逸闭包,逃逸闭包是函数返回后才执行,称该闭包在函数中逃逸。
func callback(suc: @escaping (_ code: Int,_ data: Any)->Void,failed: @escaping (_ code: Int,_ error: String)->Void) {
if true {
suc(200,"suc")
} else {
failed(404,"error")
}
}
//调用方 闭包内部使用self,闭包捕获了self,也就是self强引用闭包,闭包内部强引用self,为了避免循环引用,使用weak修饰,
callback { [weak self] (code1, data1) in
//内部使用self weak修饰,闭包捕获到self
} failed: { (code2, data2) in
}
6、自动闭包
十二:枚举
1、Swift的枚举要比OC的强大的多,可以定义构造函数、添加方法、添加属性、可以给枚举扩展、枚举可以遵循协议
2、枚举可以标明类型
//带有原始值的String类型的枚举
enum CampassPoint : String {
case north
case south
case east
case west
}
//定义一个枚举变量
var d = CampassPoint.west
//可以打印初始值,初始值就是每个枚举对应的字符串
print(d.rawValue)
//case语句匹配枚举
func xxx(direct: CampassPoint) {
switch direct {
case .east:
print("east")
case .west:
print("west")
default:
print("other")
}
}
3、枚举遵循协议,直接在枚举名后边 ,协议名 即可
enum CampassPoint : String,CaseIterable {
case north
case south
case east
case west
}
4、枚举成员的遍历 遍历上边定义的枚举CampassPoint
//allCases 是CaseIterable协议里的只读变量
for item in CampassPoint.allCases {
print(item)
}
5、关联值
//官方示例:
//可以这么理解,定义了一个枚举Barcode,它定义了一个(int,int,int,int)类型关联值的upc,另一个定义了带有(String)类型关联值的qrCode
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
//定义productBarcode变量
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
//同一个商品被分配了不同的条形码
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
//关联值可以提取出来成为switch的一部分,可以使用var或者let赋值一个变量或者常量
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case .qrCode(let productCode):
print("QR code: \(productCode).")
}
// 打印“QR code: ABCDEFGHIJKLMNOP.”
6、原始值的隐式赋值,如果原始值的类型是String时,每个枚举成员的原始值就是成员名
venus向下依次是2,3...
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
//枚举成员String类型
enum CompassPoint: String {
case north, south, east, west
}
7、递归枚举 在枚举成员前边加上 indirect 关键字来标识该成员可递归,目前不知道使用场景。略
十三:结构体
Swift结构体和类都可以:
- 定义属性用于存储值
- 定义方法用于提供功能
- 定义下标用于使用下标来操作结构体
- 定义构造器用于设置初始值
- 可用扩展extension来额外增加功能
- 都可以遵循协议来提供某些功能
结构体特有:
- 结构体是值类型,在恰当的时候Swift会生成一个结构体备份
- 结构体有逐一构造器
类特有:
- 类是引用类型
- 有继承
- 类型转换允许在运行时进行类型判定
- 析构器可释放为类示例分配的内存
- 内存管理使用引用计数
苹果推荐优先使用结构体,因为结构体更轻量级,当出现以下情况是使用类:
- 有继承的逻辑时
- 需要使用OC的API时
- 需要引用类型时 详情请移步类和结构体之间选择
本章完!