昨天的练习
swift
//(1)
//var str01 = "China"
//var str02 = "MyLove"
//var str = str01 + str02
//for a in str {
// if a == "L" {
// print(a)
// }
//}
//(2)
//一般不能直接通过检索str.index来remove str中的字符,应为在remove的时候一定会改变str原来的index;
//所以要使用filter方法筛选出符号条件的字符串
//var str = "swsvr!vrfe?123321!! 你好?世界!"
//var array : Array<Int> = [] ;
//var str01 = str.filter({$0 != "!" && $0 != "?"})
//print(str01)
//(3)
//String.Index ≠ Int;想要整数下标,先把字符串转成 [Character] 再枚举。
//var str = "abcdefg"
//var index03 = str.endIndex
//var string03 = String()
//while index03 > str.startIndex {
// index03 = str.index(before: index03)
// string03.append(str[index03])
//}
//print(string03)
//(4)
//var str = "我爱你中国"
//var index01 = str.index(after: str.startIndex)
//while index01 < str.endIndex {
// str.insert("*", at: index01)
// index01 = str.index(index01, offsetBy: 2)
//}
//var str01 = String()
//for a in str.indices {
// str01.append(str[a])
// if a < str.index(before: str.endIndex) {
// str01.append("*")
// }
//}
//print(str01)
//(5)
//var str = "abckabckabck"
//var str01 = str.replacingOccurrences(of: "abc", with: "hello")//替换对应的字符串
//(6
//var str01 = "-123"
//var str02 = "+456"
//if str01.hasPrefix("-") {
// str01.replaceSubrange(str01.startIndex..<str01.index(after: str01.startIndex), with: "+")
//}
//if str02.hasPrefix("+") {
// str02.replaceSubrange(str02.startIndex...str02.startIndex, with: "-")
//}
//(7)
//var array01 = [1,13,45,5,0,0,16,6,0,25,4,17,6,7,0,15]
//var array02 : Array<Int> = []
//for a in array01 {
// if (a != 0) {
// array02.append(a)
// }
//}
//(8)
//var array01 : Array<Int> = []
//for a in 0...9 {
// array01.append(a) ;
//}
//print(array01)
//var array02 : Array<Int> = []
//for b in array01.indices.reversed() {
// array02.append(b)
//}
//print(array02)
//(9)
//var set01 : Set<Int> = [2,4,3,5]
//var set02 : Set<Int> = [3,4,7,1]
//var set03 : Set<Int> = set01.union(set02)
//print(set03)
//(10)
var dict = ["王晓": 98,"邹明":86,"李小伟": 93 ]
//for a in dict.sorted(by: {(student1,student2) -> Bool in return student1.value > student2.value}) {
// print(a)
//}
dict.sorted(by: {$0.value < $1.value})
print(dict)
基本运算符与程序流程控制
运算符
- 赋值运算符:=
- 算数运算符:±*/%
swift不支持++,-- - 基本逻辑运算符:&& ,||,!
与oc不同,swift的逻辑运算操作数必须是Bool类型,不能使用Int - 比较运算符:<,>,>=,<=,==
元组之间的比较必须满足元组的元素个数和对应的类型相同,且比较是按位比较 - 条件运算符:m>n ? "m>n" : "m < n"
swift中的特殊运算符
空合并运算符
value = q ?? 0
q不为nil则拆包,为nil则返回第二个参数
区间运算符
var range = 0...9
...表示范围
range ~= 8
~=表示判断某个元素是否在range内
...>左闭右开区间
for- in循环结构中,如果in后是集合,则自动获取集合中的元素;如果in后是一个范围,则index获取的是从左向右一次遍历到的范围索引数
循环结构
for-in
while 先判断,后执行
repeat-while 先执行,后判断
条件选择和多分支选择结构
if与if-else结构
相较于c和oc,swift的if-else结构可以不写else结尾;
if条件都不满足就跳过不执行
逻辑值或者逻辑表达式的结果一定是Bool类型
switch-case多分支选择结构
相较于c与oc,swift的switch-case结构不需要手写break,只要符合case的条件,执行完后就会退出
case可以有多个匹配条件,满足一个就会执行
匹配条件可以是区间范围
进行元组的匹配时,分为完全匹配,选择匹配,范围匹配
swift
var charac = (1,2,3)
switch charac {
case (1,2,4) :
print("a")
case (1,2,_) :
print("b")
case (1...3,1...3,1...3) :
print("c")
default :
print("other")
}
var char = "b"
switch char {
case "a","b","c" :
print("a")
case "d" :
print("b")
case "e" :
print("c")
default :
print("other")
}
- case子句还可以捕获switch元组的参数,在相应的case代码中可以直接使用捕获到的参数
- case子句捕获switch元组参数时,还可以对捕获到参数进行判断 ,使用where语句
swift
var tuple = (0, 2)
switch tuple {
case (let a, 1) :
print("a")
case (1,let b) :
print("b")
case (let a, let b) where a == b :
print("a, b")
default :
print("other")
}
swift语言中的流程跳转语句
continue,break
- continue:跳过本次循环
- break:中断循环结构
swift
for index in 0...9 {
if index == 6 {
continue//跳过本次循环
}
print(index)
}
MyLabel : for index01 in 0...9 {
for index02 in 0...9 {
if (index02 == 6) {
continue MyLabel//跳过本次指定的循环
}
}
}
for index03 in 0...9 {
if (index03 == 6) {
break
}
print(index03)
}
fallthrough
在实际开发中需要switch-case结构不自动进行中断操作,可以使用fallthrough ;
swift
var tuple = (0, 0)
switch tuple {
case (0,0) :
print(1)
fallthrough
case (_,0) :
print(2)
fallthrough
case (0,_) :
print (3)
fallthrough
default :
print(4)
}
return
返回值,和c/oc一样
throw
先跳过。不是特别懂,后面要学
guard-else
一般用于当参数符合某个条件时,函数才能正常执行,否则直接通过return来终止函数的执行
swift
func myfuncTwo (param:Int) {
guard param>0 else {
return
}
print(param)
}
练习
swift
//练习
//(1)
//var intPrice = 5 * 2 + 1 * 3
//var doublePrice = 2.5 * 3 + 0.5 * 11
//var sum = Double(intPrice) + doublePrice
//(2)
//var rand = arc4random() % 7 + 1 //随机数函数
//(3)
//var a = 65
//var b = 65
//var c = 70
//if a > 60 && b > 60 && c > 60 && a + b + c >= 200 {
// print("优秀")
//}
// (4)
//var year = 2016
//if year % 400 == 0 || ((year % 4 == 0) && (year % 400 != 0 ) ) {
// print("闰年")
//}
// (5
//var mark = 40
//print(mark > 30 ? "主选手" : "副选手")
// (6)
//for a in 0...3 {
// for b in 0...9 {
// if (a == 0 || a == 3) {
// print("*", separator: "", terminator: "")
// } else if (b == 0 || b == 9) {
// print("*", separator: "", terminator: "")
// } else {
// print("?", separator: "", terminator: "")
// }
// }
// print("") //换行
//}
// (7)
//for num in 100...999 {
// var a = num % 10
// var b = num / 10 % 10
// var c = num / 100 % 10
// if (a * a * a + b * b * b + c * c * c == num) {
// print(num)
// }
//}
//(8)
//var count = 1
//for _ in 1...9 {
// count = (count + 1) * 2
//}
//print(count)
函数与闭包技术
闭包是没有名称的函数,类似oc中Block块
函数的基本应用
函数的创建和调用
func isMoreThanTen (cout : Int) -> Bool
- func为函数声明关键字
- 函数三要素:函数名,参数,返回值
- 参数列表的函数需要指定参数名和参数类型,也可以编写无参的函数
- 也可以无返回值
swift
func isMoreThanTen (cout : Int) -> Bool {
if (cout > 10) {
return true
} else {
return false
}
}
isMoreThanTen(cout: 11)
func myFunc01 () -> String {
return "hello"
}
myFunc01()
func myFunc02 () {
print("world")
}
myFunc02()
- swift可以通过返回元组的形式,返回多个返回值
swift
func searchData (dataID : String) -> (succsee: Bool, data : String) {
return (true, "data")
}
- 开发者可以通过返回Optional类型值来标识函数的执行是否成功,在调用函数时使用if-let结构进行安全性检查
swift
func myFunc04 (param : Int) -> Int? {
guard param > 100 else {
return nil
}
return param - 100
}
if let temp = myFunc04(param: 110) {
print(temp)
print(type(of: myFunc04(param: 110)))
} else {
print("nil")
}
关于函数的参数名
swift引入了内部命名和外部命名,内部命名在函数实现时使用,外部命名在函数调用时使用
swift
func myFunc05 (out param01 : Int, out param02 : Int,out param03 : Int) -> Int {
return param01 + param02 + param03
}
myFunc05(out: 3, out: 12, out: 46)
- swift如果省略函数参数的外部名称时,一般默认外部名称和内部名称相同;但如果使用"_"省略外部名称时,在调用函数时,不再标识参数名称
swift
func myFunc06 (_ param01 : Int, _ param02 :Int, _ param03 : Int) -> Int {
return param01 + param02 + param03
}
myFunc06(3, 12, 46)
函数中参数的默认值,不定数量参数与inout类型参数
- swift语言中函数的参数也支持设置默认值 :
swift
func myFunc07 (out01 param01 : Int, out02 param02 : Int = 16,out03 param03 : Int = 59) -> Int {
return param01 + param02 + param03
}
myFunc07(out01: 3)
- swift还可以编写参数个数不定的函数,比如printf;
- 在参数类型后加上...,即设置此参数个数不定;在函数内部,会将开发者传递的多个参数包装成一个集合对象,在内部通过for- in结构获取多个参数
swift
func myFunc08 (param01 : Int...) -> Int {
var sum = 0
for a in param01 {
sum += a
}
return sum
}
myFunc08(param01: 1,3,5)
- swift语言的函数具有和oc中Block类似的性质,就是对值类型的参数会捕获它的值,如果在函数内部去修改这个值类型的参数就会报错 ;如果要去修改值类型的参数,需要在参数类型前加上inout关键字
- inout类型修饰的值类型参数要传入内存地址,也就是使用"&"
swift
var param = 10 ;
func myFunc09 (param01 : inout Int) -> Int {
param01 += 1
return param01
}
myFunc09(param01: ¶m)
函数的类型与函数嵌套
函数的类型由参数和返回值的类型和个数决定
如(Int,Int) -> Int
因为函数有类型了,所以我们可以声明对应的函数变量
可以对函数变量进行赋值和调用操作
甚至允许一个函数作为另一个函数的参数或返回值进行调用
- 闭包的格式:{(param01 : Int, param02 : Int) in 代码块}
swift
var addFunc: (Int, Int) -> Int
addFunc = {(param01 : Int, param02 : Int) in return param01 + param02}
addFunc (1, 2)
func myFunc13 (param01 : Int, param02 : Int) -> Int {
return param01 + param02
}
addFunc = myFunc13
addFunc (1,45)
func myFunc14 (param01: (Int,Int) -> Int) -> Void {
print(param01(4,6))
}
myFunc14(param01: addFunc)
- 开发者也可以在函数内部再次创建函数
swift
var addFunc : (Int, Int) -> Int
func myFunc15 () -> (Int, Int) -> Int {
return {(param01 :Int, param02 : Int) in return param01 + param02}
}
addFunc = myFunc15()
addFunc (3,9)
func myFunc16 () -> (Int, Int)-> Int {
func subFunc (param01 : Int, param02 :Int) -> Int {
return param01 + param02
}
return subFunc(param01:param02:)
}
addFunc = myFunc16()
addFunc(98,34)
理解闭包结构
闭包的语法结构
{(参数) -> (返回值类型) in 代码实现 }
swift
let myclosures = {(param01 : Int) -> Int in return param01 * param01 } ;
myclosures(2)
- 与函数不同的是,闭包可以不声明返回值的类型,可以自动识别闭包返回值的数据类型
swift
let myclosures = {(param01 : Int) in return param01 * param01 } ;
myclosures(2)
通过实现一个排序函数来深入理解闭包
- mySort()函数要传入两个参数,一个是要进行排序的数组数据。一个是排序规则(闭包)
- swapAt()是array的交换方法
- 由于array也属于值类型,我们在函数内部对它进行修改的时候需要使用inout修饰
- as!的作用是类型转换
swift
func mySort (array:inout Array<Any>, sortClosure:(Any, Any)->Bool) -> Array<Any> {
for a in array.indices {
if (a == array.count - 1) {
break
}
for b in 0...((array.count - 1) - a - 1) {
if sortClosure(array[b], array[b + 1]) {
} else {
array.swapAt(b, b + 1)
}
}
}
return array
}
class Student : CustomStringConvertible {
let achevement : Int
let name : String
init(achevement: Int, name: String) {
self.achevement = achevement
self.name = name
}
var description: String {
return "\(name):\(achevement)"
}
}
let stu1 = Student(achevement: 89, name: "小王")
let stu2 = Student(achevement: 69, name: "小李")
let stu3 = Student(achevement: 81, name: "小张")
let stu4 = Student(achevement: 93, name: "小孙")
var array : Array<Any> = [stu1,stu2,stu3,stu4]
mySort(array: &array, sortClosure: {(stu01 : Any, stu02 : Any) in
return (stu01 as! Student).achevement < (stu02 as! Student).achevement
})
print(array)
上面模拟了一个学生类,每一个学生对象由名字和分数组成,闭包实现了对学生分数的排序规则
- 由这个例子可以看出,相对于c/oc,swift允许将函数作为参数的特性,使得我们可以把自定类之间的比较规则作为一个参数传递,其表现形式就是一个闭包(代码块)
将闭包作为参数传递时的写法优化
- 闭包允许省略返回值的类型,它会自动识别返回的值的数据类型
- 当闭包作为函数的参数时,闭包的参数类型可省略
- 如果闭包的代码块只有一行代码,return也可以省略
- 闭包甚至可以省略掉参数列表和闭包关键字in;参数可以用自动生成的0,1...
最终表现为:
swift
//mySort(array: &array, sortClosure: {(stu01 : Any, stu02 : Any) in
// return (stu01 as! Student).achevement < (stu02 as! Student).achevement
//})
mySort(array: &array, sortClosure: {
($0 as! Student).achevement < ($1 as! Student).achevement
})
后置闭包,逃逸闭包和自动闭包
这是调用的时候,不是声明的时候
- 当函数的最后一个参数为闭包参数时,在调用函数时,开发者可以将闭包结构脱离出函数的参数列表,追加在函数的尾部,增强代码的可读性
swift
//后置闭包
mySort(array: &array) {
($0 as! Student).achevement < ($1 as! Student).achevement
}
- 如果函数只有一个参数,且这个参数为闭包参数,使用后置闭包的写法可以直接将函数的参数列表省略
swift
func myFunc (closure :(Int, Int) -> Bool) {
print(closure (3,9))
}
myFunc {$0 + $1 > 10}
-
闭包分为逃逸闭包和非逃逸闭包;闭包传递进函数的时候,系统会为此闭包进行内存的分配
-
逃逸闭包在函数内外都可以使用,可以作为返回值返回
-
非逃逸闭包只能在函数内部使用,会随着函数的生命周期结束而销毁,可以提高代码性能,节省内存消耗
-
默认定义的闭包和参数中的闭包都是非逃逸类型
-
只要闭包可能在函数返回后执行,参数前加 @escaping 即可定义逃逸闭包。
-
swift还可以实现对简单闭包的自动生成,也就是自动闭包
-
当闭包没有参数,且闭包的代码块里只有一句表达式,闭包的返回值即为此表达式的值;就可以使用自动闭包
-
由@autoclosure声明
swift
func myFunc2 (_ closure: @autoclosure () -> Bool) {
}
myFunc2( 1 + 2 > 3 )
- 注意:自动闭包省略的是代码块,参数名是否省略要看外部参数名有没有使用"_"省略
高级运算符和枚举
位运算符与溢出运算符
位运算符
swift
var a : UInt8 = 8
var b : UInt8 = 0b1000
a = ~a
a = 0b11110000&a
a = 0b11111111|a
a = 0b11110000^a
a = a << 1
a = a >> 1
左移和右移可能会出现丢失数据位的情况
溢出运算符
一般如果出现了数据溢出,运行时会错误;
如果需要溢出操作的话,可以使用溢出操作符
swift
var b :UInt8 = 255
b = b &+ 1
b = b &- 1
b = b &* 2
运算符的重载与自定义
重载运算符
- 对同一个函数名设置不同的参数类型以实现不同的功能被称为函数的重载
- 运算符重载的形式类似于函数,或者说运算符就是函数
swift
class Circle {
var center : (Double,Double)
var radius:Double
init(center: (Double, Double), radius: Double) {
self.center = center
self.radius = radius
}
}
func + (param01 : Circle, param02 : Circle) -> Circle {
return Circle(center: param01.center, radius: param01.radius + param02.radius)
}
let c1 = Circle(center: (0,0), radius: 1)
let c2 = Circle(center: (1,1), radius: 1)
let c3 = c1 + c2
print(c3.radius)
- 运算符也可以当成函数名使用,比如作为函数参数传入
- 重载和覆写完全不一样
自定义运算符
以下是三种自定义运算符的声明和实现方式:
swift
prefix operator ++
prefix func ++ (param01 : Int) -> Int {
return param01 + 1
}
let a = ++1
infix operator ++
func ++ (param01 : Int, param02 : Int) -> Int {
return param01 * param01 + param02 * param02
}
let b = 1 ++ 2
postfix operator ++
postfix func ++ (param01 : Int) -> Int {
return param01 + param01
}
let c = 1++
运算符的优先级与结合性
和c/oc语言差不多,用的时候查表就行
- 重载不改变运算符的结合性和优先级
- 自定义运算符的时候,可以设置为系统内置的优先级组
- 如果系统内置的不满足需求,就使用precedencegroup来自定义优先级组
swift
// 定义一个名为customGroup的运算符优先级组
precedencegroup customGroup {
// 设置customGroup的优先级高于加法运算符优先级组(AdditionPrecedence)
higherThan : AdditionPrecedence
// 设置customGroup的优先级低于乘法运算符优先级组(MultiplicationPrecedence)
lowerThan : MultiplicationPrecedence
// 指定该优先级组是否用于赋值操作,true表示可用于赋值
assignment : true
// 设置运算符的结合性为从左到右
associativity : left
}
// 声明一个中缀运算符+++,并指定其优先级组为上面定义的customGroup
infix operator +++ : customGroup
infix operator *** : AdditionPrecedence
枚举类型的创建和应用
声明一个枚举类型的变量后,赋值的时候可以省略枚举类型的名称,直接调用点语法
枚举类型常用于switch-case结构
如下:
swift
enum Surname {
case 张
case 王
case 李
case 赵
}
var sur :Surname
sur = Surname.张
sur = .李
switch sur {
case .张:
print("姓张")
case .王:
print("姓王")
case .李:
print("姓李")
case .赵:
print("姓赵")
}
枚举的原始值与相关值
枚举的原始值
声明原始值类型:
swift
enum CharEnum :Character {
case a = "a"
case b = "b"
case c = "c"
case d = "d"
}
Int类型的原始值默认递增加1,可省略
swift
enum IntEnum : Int {
case one = 1
case two
case three
case four
}
既可以通过rawvalue获取原始值,也可以通过它初始化枚举类型的值
swift
var char = CharEnum.a
var rawvalue = char.rawValue
var intEnum = IntEnum(rawValue: 1)
//可能rawValue是没有对应的枚举值的,所以返回的是optional值
枚举的相关值
可以为枚举值以参数列表的形式来添加对应的相关值
swift
enum Shape {
case circle (center : (Double,Double), radius : Double)
case rectangle (center : (Double,Double), width: Double, height: Double)
case triangle (point01 : (Double, Double), point02 : (Double,Double), point03 : (Double, Double))
}
var circle = Shape.circle(center: (0,0), radius: 2)
var rect = Shape.rectangle(center: (0,0), width: 2, height: 4)
var tri = Shape.triangle(point01: (2,4), point02: (3,5), point03: (2,5))
func shapeFunc (param01 : Shape) {
switch param01 {
case let .circle (center, radius) :
print("圆心:\(center) 半径:\(radius)")
case let .rectangle (center, width, height) :
print("矩形中心:\(center) 宽:\(width) 高:\(height)")
case let .triangle (point01, point02, point03) :
print("三角形顶点:\(point01) \(point02) \(point03)")
}
}
shapeFunc(param01: circle)
shapeFunc(param01: rect)
shapeFunc(param01: tri)
- 这里的let是表示获取到拆包后的数据
递归枚举
这部分以后碰到了再看了