- swift函数和返回值
func sum(num1:Int,num2:Int) -> Int {
return num1 + num2
}
- 外部参数:外部参数就是在形参前加个名字,不会影响函数内部实现
外部参数如果使用''在外部调用函数时,会忽略形参的名字
在swift中如果使用''就是可以忽略任何不感兴趣的内容
print(sum1(1, 3))//使用'_'num1和num2直接忽略
func sum1(_ num1:Int,_ num2:Int) -> Int {
return num1 + num2
}
//任何不感兴趣的东西都可以用'_'替代
let i = 5
for _ in 0...i {
print("你好")
}
- 默认值.通过给参数设置默认值在调用是可以任意指定参数,如果不指定就使用默认值.OC中需要定义很多的方法和实现,最终调用很多方法,swift就方便了很多.
//任意都可以调用非常灵活.不用创建太多的方法了.并且方法设置默认值,没有给参数就直接使用默认值
sum2()
sum2(num1: 1, num2: 1)
sum2(num1:3)
sum2(num2: 3)
func sum2(num1:Int = 1,num2:Int = 2) -> Int {
return num1 + num2
}
- 无返回值的情况,主要用在闭包
- 直接省略
- ()
- void
前面代表执行->传递给此输出
//swift函数一定是() -> ()格式,大部分是省略写法,注意了解清楚
//无返回值情况1
func demo1() {
print("无返回值情况1其实省略了-> ()返回值")
}
//无返回值情况1
func demo2() ->() {
print("无返回值情况1其实省略了-> ()返回值")
}
//无返回值情况1
func demo3() -> Void {
print("无返回值情况1其实省略了-> ()返回值")
}
- 闭包:类似与OC的block,但是比block应用更广.
定义:- 提前准备好的代码
- 在需要的时候执行
- 可以当做参数传递
特点:
1. swift中变量可以用来记录函数,写下代码.并且通过变量调用它.
2. 写一个最简单的闭包,带参数的闭包,带参数和返回值的闭包
3. 闭包中参数,返回值,实现代码都写在{}中,但是需要使用关键字in(分隔定义和实现)
4. 如果没参数,返回值都可以以连in也可以省略.
5. 要确定是什么类型是不是闭包按快捷键看其类型.
//使用常量记录函数
let f = sum
print(f(10,20))
func sum(num1:Int,num2:Int) -> Int {
return num1 + num2
}
//定义一个最简单的闭包
let b1 = {
print("我是最简单的闭包")
}
b1()
//定义一个最简单的block,注意in省略了
void (^block1)() = ^{
};
void (^block1)变量block1,对应let b1(swift可以自动推导省去了复杂的格式),=右边的除了^其他都一样非常像
//带参数的闭包,注意swift中的闭包的参数是写在{}内的并且使用in分隔
let b2 = { (num:Int) -> () in
print("打印参数 \(num)")
}
b2(20)//这里面的'-> ()'可以省略
//带参数带返回值的闭包
let b3 = { (num1:Int,num2:Int) -> (Int) in
return num1 + num2
}
print(b3(10,20))
使用场景.闭包的应用场景和block完全一致.
1. 异步执行的回调
2. 控制器回调
3. 自定义视图回调
//写一个异步执行请求数据的逻辑代码
//场景1:将任务添加进队列,指定执行任务的函数
DispatchQueue.global().async {
//执行耗时操作
print("耗时操作 \(Thread.current)")
//假设有结果,主队列回调
DispatchQueue.main.async(execute: {
//主线程更新UI
print("主线程更新UI \(Thread.current)")
})
}
//场景2:控制器回调
1. 参照以前写block是直接声明一个属性block,如果此属性存在(函数被调用),就实现属性block就参数传递过回去并且pop.当pop回的控制器里面写了setBlock方法时就能拿到逆向传递的属性值.闭包又如何实现呢?
闭包实现:
1. 定义闭包属性(注意开始闭包是没有值的后面才指向函数所以要用var)一个函数类型的变量可以(可选的可以为nil可以指向函数实现)
var popVcGetName:((_ name:String) -> Void)?
或者var popVcGetName:PopVcGetName?
2. 如果直接设置属性类型为函数类型就不用实现此步骤.否则使用typealias(为已存在的类型重新命名).然后指定属性为此PopVcGetName类型
typealias PopVcGetName = (_ name:String) -> Void
3. 判断闭包是否实现实现就调用
if popGetName != nil {
popGetName!(name)
//pop控制器
self.navigationController?.popViewController(animated: true)
}
4. 传递闭包此处就能获取到逆向传递的值,但是因为swift没有set属性的设置只能在后面转换
zlVc.popVcGetName = { name:String Void in
print("zlvc反向传递来的\(name)")
}
//场景3:自定义视图
和场景二基本相同,但是是通过控件对象传递
- 尾随闭包:注意关键点是尾如果函数的最后一个参数是闭包,函数参数可以提前结束,最后一个参数用{}封装闭包的代码所以不要以为{}就不会是闭包了.
大多数情况下Xcode会帮我么补齐,有个奇怪的地方尾随闭包内的包含尾随闭包没有办法自动补齐会变成(参数:{})这个样子
例子:
DispatchQueue.global().async(execute: () -> Void)回车展开后变为
DispatchQueue.global().async {
code
}
DispatchQueue.global().async {
//执行耗时操作
print("耗时操作 \(Thread.current)")
//假设有结果,主队列回调
DispatchQueue.main.async(execute: {
//主线程更新UI
print("主线程更新UI \(Thread.current)")
})
}
改为这样也可以.所以都是尾随闭包
DispatchQueue.global().async {
//执行耗时操作
print("耗时操作 \(Thread.current)")
//假设有结果,主队列回调
DispatchQueue.main.async {
//主线程更新UI
print("主线程更新UI \(Thread.current)")
}
}
- 闭包存在的循环引用的情况
类似block,闭包也存在循坏引用和block类似,应该也是在堆上开辟了新的内存空间闭包内会继续引用强指针指向的对象.在控制器释放后也不会释放
- swift闭包的三种解决办法(XCode可以看到视图对象来查看是否循环引用在显示图层那一行)
1.类似OC方式
weak var weakSelf = self
//细节1:weakSelf会在对象释放置为nil所以var才能修饰
//细节2:如果self已经被释放!会导致崩溃可以采用?可选解包,如果对象已经被释放不会像对象发送getter消息
loadData = {
print(weakSelf?.view)
}
2. swift方式[weak self]表示闭包中的self都是weak
loadData = { [weak self] in
print(weakSelf?.view)
}
3. [weak self]表示闭包中的self都是assgin,对象被释放还是会指向原来地址,调用对象的相关方法被崩溃.会产生悬垂指针.
loadData = { [weak self] in
print(weakSelf?.view)
}
- 敲个加法计算器(作为语法的巩固,纯代码)
快捷键cmd + ctrol + E全选所有词替换
网友评论