常见的操作符
-
optional:
var a:Int? -
解包:```var value:Int
if(a != nil){
value = a!} else {
value = 0
}```
-
合并空运算符:
value = a ?? 0 -
区间运算符:
var range = 0...10var range2 = 0..<10. "..." 或者 "..<" -
检查某个数字是否在这个 range 中:
~=,range ~= 8: range 中是否包含8这个数字
流程控制
//switch, 不需要通过 break 跳出,匹配到一个之后,会自动停止匹配
var charactor = "a"
switch (charactor)
{
case "a":
print("charator is a")
default:
break
}
//如果匹配之后,要再次匹配可以用 fallthrough
switch (charactor)
{
case "a":
print("charator is a")
fallthrough
case "b":
print("charator is b")
fallthrough
case "c":
print("charator is c")
default:
break
}
var tuple = (1,1)
switch (tuple)
{
case (let a, 1):
print(a)
case (let b, 0):
print(b)
case (let a, let b):
print(a,b)
}
switch (tuple)
{
case (let a, 1) where a == 1:
print(a)
case (let b, 0):
print(b)
case (let a, let b):
print(a,b)
}
//continue
MyLabel:for _ in 0...10{
for _ in 0...10{
for index3 in 0...10{
if (index3 == 6){
continue MyLabel
}
print(index3)
}}}
//guard else
func myFunc(param:Int)->Int{
guard param > 0 else{
return 0
}
print("do something else")
return 1
}
函数和闭包
- 函数结构:
func method( param1,param2,...)->return value{实现部分}
- 返回 optional 类型
func search2(dataId:Int)->Int?
{
guard dataId > 100 else {
return nil
}
return dataId-100
}
- 匿名变量
func myFunc2(_ param1:Int, _ param2:Int)->Int{
return param1 + param2
}
var ret = myFunc2(1, 2)
- 可变参数: 形参会被包装成一个集合类型赋值给对应的参数,但是传递的参数类型必须相同,并且可以传递多组数量可变的参数,不同参数之间参数类型可以不同
func myFunc3(param:Int...)->Int
{
var sum = 0
for value in param{
sum += value
}
return sum
}
myFunc3(param: 1,2,3,4,5)
//多参数
func myFunc4(param1:Int..., param2:String...)
{
for value in param1{
print(value)
}
for value in param2{
print(value)
}
}
myFunc4(param1: 1,2,2,3, param2: "hi","你好")
-
注意,如果传递的是值类型的参数,那么参数值在传递进函数内部时会将原值复制为一个常量,且在函数内部不可修改,“基本数据类型,枚举,和结构体都是属于值类型”
-
如果真的需要在函数内部修改传递参数的变量值,可以将此参数声明为
inout类型,在传递参数的时候需要加上&符号,这个符号传递参数变量的内存地址 -
函数变量: 下列代码通过闭包的方式对
addFunc进行了赋值
var addFunc:(Int, Int)->Int
addFunc = {(param1:Int, param2:Int) in return param1 + param2}
addFunc(2,3)
-
闭包实质上是一段有具体功能的代码块,结构为
{(param1, param2, ...)in 代码块}, 如果代码块里面有返回值,就可以省略返回类型,可以推导返回值类型 -
函数作为入参
var plusFunc:(Int, Int)->Int
func myFunc6(param1:Int, param2:Int)->Int{
return param1 + param2
}
plusFunc = myFunc6
plusFunc(2,3)
func printFunc(param:(Int, Int)->Int, param1:Int, param2:Int)
{
print(param(param1,param2))
}
printFunc(param: plusFunc, param1: 4, param2: 5)
- 嵌套函数: 这种嵌套函数也有作用域
func myFunc8()->(Int,Int)->Int{
func subFunc(param1:Int, param2:Int)->Int{
return param1 + param2
}
return subFunc
}
- 函数作为参数,有以下例子
func mySort(arry:inout Array<Any>, sortClosure:(Any,Any)->Bool)->Array<Any>{
for indexI in arry.indices {
if indexI == arry.count - 1{
break
}
for indexJ in 0...((arry.count - 1)-indexI-1){
if sortClosure(arry[indexJ], arry[indexJ + 1])
{
}
else
{
arry.swapAt(indexJ, indexJ+1)
}
}
}
return arry
}
mySort(arry: &array) { (i:Any, j:Any) in
return (i as! Int) < (j as! Int)
}
print(array)
-
as!类型强转, 当闭包的代码块只有一行代码,也可以省略return -
后置闭包,当函数的最后一个参数为闭包参数,在调用函数时,可以将闭包结构脱离出函数的参数列表,追加在函数的尾部,增加代码可读性
mySort(arry: &array){
($0 as! Int) > ($1 as! Int)
}
//如果只有闭包一个入参,也可以省略参数列表
myFunc{
$0 > $1
}
- 逃逸闭包和非逃逸闭包, 当闭包传递进函数的时候,会为闭包进行内存分配。逃逸闭包,是指在函数内的闭包在函数执行结束之后,在函数外还是可以调用。非逃逸闭包,是指在函数生命周期结束后,闭包也会被销毁。默认情况下,函数参数中的闭包都为非逃逸闭包,提高性能,节省内存,同时非逃逸闭包也不能作为返回值,编译时就会出错。
//逃逸闭包声明
func myFunc(closure:@escaping()->Bool)
- 自动闭包, 实现相对简单的闭包,可以通过自动闭包实现
func myFunc(closure:@autoclosure()->Bool){
}
//调用直接传一个表达式就可以了
myFunc(a>b)
swift 高级运算符和枚举
- 符号重载
class Circle{
var center:(Double,Double)
var radius:Double
init(center:(Double,Double), radius:Double){
self.center = center
self.radius = radius
}
}
func +(param1:Circle,param2:Circle)->Circle{
return Circle(center:param1.center, radius: param1.radius + param2.radius)
}
在某些情况下函数参数是闭包,比如:
func myFunc(closure:(Circle,Circle)->Circle){
}
//可以直接传入上述代码中定义个加法
myFunc(closure:+)
- 自定义运算符:在 swift 2.2 之后的版本就移出了 ++ -- 的操作, prefix/infix/postfix 分别代表前中后操作符的声明,其中 prefix/postfix 都只能接收一个参数,func 实现的时候,需要在前面加上 prefix/postfix. infix 接收两个参数,因此不需要在 func 实现的时候加上 infix
prefix operator ++
prefix func ++(param:Int)->Int{
return param+1
}
- 自定义操作符的优先级
precedencegroup customGroup{
higherThan:AdditionPrecedence//优先级比加法高
lowerThan:MultiplicationPrecedence//优先级比乘法低
assignment:true//设置执行可选链操作时的优先级
associativity:left//结合性
}
infix operator +++:customGroup
infix operator ++++:AdditionPrecedence
- 枚举
enum SuperName{
case zhang
case 张
case wang
case 王
}
var sur:SuperName = SuperName.zhang
var sur2:SuperName = .wang
- 枚举的原始值: 在创建一个枚举的时候,可以声明一个原始值类型,并将某个已经存在的类型的值和枚举值进行绑定
enum CharEnum:Character{
//通过赋值的方式为枚举值设置一个原始值
case a = "a"
case b = "b"
case c = "c"
}
//如果指定原始值类型为 Int 类型,那么可以只设置第一个枚举值的原始值,后面的枚举值会在前一个枚举值的原始值上递增
enum IntEnum:Int{
case yi = 1
case er
case si = 4
case wu
}
let intEnum1:IntEnum = .wu
print(intEnum1.rawValue)
//通过原始值构造枚举变量
var intEnum2 = IntEnum(rawValue:1)
swift 类与结构体
- 类是引用类型比较引用类型只能用等同运算符"===", 是对地址的比较,结构体是值类型
class Car
{
var brand:String
var price:Double
init(brand:String, price:Double)
{
self.brand = brand
self.price = price
}
}
var car1:Car = Car(brand: "BMW", price: 310000)
var car2 = car1
//let isSameObj = car1==car2 //编译错误
//print(isSameObj)
var car3 = Car(brand: "BMW", price: 310000)
let isSame = car1===car3
print(isSame)//false, 是对地址的比较
struct Person{
var name:String
var age:Int
mutating func growUp()//结构体更改结构体的属性,需要加 mutating
{
age += 1
}
}
存储属性&计算属性
- 存储属性:用于定义类或结构体的某些特征,用变量或者常量存储某些有意义的值。只能用于类和结构体
类的原则: 当类被构造完成时,必须保证类中所有属性都构或者初始化完成,因此类中提供一个构造方法用于设置其中的属性,但也可以在属性声明的时候就提供一个初始值
class Student{
var name:String
var age:Int
let schoolName = "一中" //声明时初始化
init(name:String, age:Int){
self.name = name
self.age = age
}
}
//如果schoolName不初始化,init 上述的写法就会报错
class Student{
var name:String
var age:Int
let schoolName:String
init(name:String, age:Int){
self.name = name
self.age = age
self.schoolName = "一直"
}
}
var st = Student(name: "sss`", age: 15)
//不一定需要构造函数传所有的参数,只需要保证在构造函数体内,所有存储属性都初始化
-
注意:当值类型的实例是 let 修饰的,那么存储属性是不能修改的。对于引用类型,无论是 let 还是 var,存储属性不是由 let 修饰的,都能够被修改
-
对于存储属性,还支持将存储属性设置为延时存储属性。延时存储属性是指在类实例构造的时候,延时存储属性并不进行构造或者初始化,只有当调用类实例这个属性的时候,这个属性才完成构造或初始化操作。示例如下
class Persons {
var age:Int
lazy var st:Student = Student(name: "mmm", age: 18)
init(age:Int)
{
self.age = age
}
}
- 计算属性:计算属性更像一中运算过程,比如一个圆,只需要知道圆心和半径,就可以得到周长和面积,所以就不需要额外定义存储属性去存储周长和面积。在通过 set 方法设置存储属性的时候,新值会以 newValue 的名字传入,当然也可以自定义
set(myValue){}的方式来存储这个传入的值. 注意: 计算属性的 get, set 方法,get 方法是必须的,set 方法是可选的。
class Circle1{
var r:Double
var center:(Double,Double)
var l:Double{
get {
return 2*r*Double.pi
}
set{
r = newValue/2/Double.pi
}
}
var s:Double{
get{
return r*r*Double.pi
}
set(myValue)
{
r = sqrt(myValue/Double.pi)
}
}
init(r:Double, center:(Double,Double))
{
self.r = r
self.center = center
}
}
var circle1 = Circle1(r: 2, center: (2, 2))
属性监听器
属性监听器:用于监听存储属性的赋值的过程,并且可以自己编写代码,添加额外的逻辑。在进行属性的构造或初始化时,无论是通过构造方法进行属性构造或初始化,还是为属性设置默认值,都不会调用属性监听的方法。初始化后从第2次为属性赋值开始,属性监听器才会被调用
class Teacher{
var name:String{
willSet{
print("will set teacher name:\(newValue)")
}
didSet{
print("did set teacher name:\(oldValue)")
}
}
init(name:String)
{
self.name = name
}
}
- 注意:默认用 oldValue来保存老值, newValue 来保存新值。当然也可以自定义
willSet(myNew){}