Swift语法基础入门三(函数, 闭包)

函数:

  • 函数是用来完成特定任务的独立的代码块。你给一个函数起一个合适的名字,用来标识函数做什么,并且当函数需要执行的时候,这个名字会被用于“调用”函数
  • 格式:
  • func 函数名称(参数名:参数类型, 参数名:参数类型...) -> 函数返回值 { 函数实现部分 }

没有参数没有返回值

  1. 可以写为 ->Void
  2. 可以写为 ->()
  3. 可以省略
  4. Void。它其实是一个空的元组(tuple),没有任何元素,可以写成()
func say() -> Void {
print("hello")
}
say() func say1() -> () {
print("hello")
}
say1() // 推荐
func say2() {
print("hello")
}
say2()

有参数没有返回值

内部/外部参数

  • 内部参数: Swift2.0以前, 默认情况下的参数都是内部参数
  • Swift2.0开始, 默认将第二个参数名称作为外部参数
  • 如果没有明确地指定外部参数, 那么系统默认会从第二个参数开始, 将参数的名称作为外部参数
  • 外部参数只能外部用, 函数内部不能使用, 函数内部只能使用内部参数
  • 忽略外部参数: 在内部参数前加_
// Swift2.0之前, 默认是不会将第二个参数开始的参数名称作为外部参数的, 必须自己手动指定
func sum(i: Int, j: Int) {
print(i + j)
}
sum(10, j: 20) func sum1(first i: Int, second j: Int) {
print(i + j)
}
sum1(first: 10, second: 20)

默认参数(Default Parameter Values)

  • 格式: func method(parameter: Int = 0){}
  • 当默认值被定义后,调用这个函数时可以忽略这个参数
  • 其它语言的默认参数必须写在最后面, Swift可以写在任意位置

注意

  • 将带有默认值的参数放在函数参数列表的最后。这样可以保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不同情况下调用时显得更为清晰。
func sum2(i: Int, j: Int = 10) {
print(i + j)
}
//sum2(10, j: 20)
sum2(10) // 不推荐这样写, 最好将默认参数写在最后
func sum3(i: Int = 20, j: Int) {
print(i + j)
}

常量参数和变量参数(Constant and Variable Parameters)

  • 函数参数默认是常量, 在函数内部不能修改
  • 如果想在函数中修改参数, 必须在参数前加上var

注意

  • 对变量参数所进行的修改在函数调用结束后便消失了,并且对于函数体外是不可见的。变量参数仅仅存在于函数调用的生命周期中
func sum4(let i: Int, let j: Int) {
print(i + j)
}
sum4(10, j: 20) var num1 = 10
var num2 = 20
//func swap(value1: Int, value2: Int){
// let temp = value1
// value1 = value2
// value2 = temp
//} // 注意: 操作的是局部变量, 对实参没有影响
func swap1(var value1: Int, var value2: Int){
print("交互前: value1 = \(value1), value2 = \(value2)")
let temp = value1
value1 = value2
value2 = temp
print("交互后: value1 = \(value1), value2 = \(value2)")
} swap1(num1, value2: num2)
print(num1)
print(num2)

输入输出参数(In-Out Parameters)

  • 变量参数,正如上面所述,仅仅能在函数体内被更改。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数(In-Out Parameters)
  • 定义一个输入输出参数时,在参数定义前加 inout 关键字

注意

  • 输入输出参数不能有默认值,而且可变参数不能用 inout 标记。如果你用 inout 标记一个参数,这个参数不能被 var 或者 let 标记。
func swap2(inout value1: Int, inout value2: Int){
print("交互前: value1 = \(value1), value2 = \(value2)")
let temp = value1
value1 = value2
value2 = temp
print("交互后: value1 = \(value1), value2 = \(value2)")
}
swap2(&num1, value2: &num2)
print(num1)
print(num2)

可变参数(Variadic Parameters)

  • 一个可变参数可以接收零个或多个值
  • 如果没有变参函数 , 并且函数的参数个数又不确定那么只能写多个方法或者用将函数参数改为集合
  • 格式 func method(parameter: Int...){}
  • 可变参数在函数中可以当做一个数组

注意

  • 一个函数最多只能有一个可变参数
  • 变参只能是同种类型的数据
  • 变参必须指定数据类型
  • 如果函数有一个或多个带默认值的参数,而且还有一个可变参数,那么把可变参数放在参数表的最后
func sum5(numbers: Int...) {
// print(numbers)
var sum = 0
for number in numbers {
sum += number
}
print(sum)
}
sum5(1, 2, 3) // 不推荐写法, 和默认值一样, 变参最好写在最后
func sum6(numbers: Int..., var sum: Int) {
// print(numbers)
for number in numbers {
sum += number
}
print(sum)
}
sum6(1, 2, 3, sum: 0) // 推荐写法
func sum7(var sum: Int = 100, numbers: Int...) {
// print(numbers)
for number in numbers {
sum += number
}
print(sum)
}
sum7(numbers: 1, 2, 3) // 一个函数中只能有一个变参
//func sum8(numbers: Int..., values: Int...){
// print(numbers)
// print(values)
//} // 有参数有返回值
func sum8(i: Int, j: Int) -> Int {
return i + j
}
let result = sum8(10, j: 20)
print(result)

闭包

闭包

  • 闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的匿名函数比较相似
  • 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。这就是所谓的闭合并包裹着这些常量和变量,俗称闭包
  • 闭包的使用和block一样, 用于保存一段代码, 用作回调, 用作执行耗时操作
  • 闭包格式: in关键字的目的是便于区分返回值和执行语句
     {
    (形参列表) -> 返回值类型
    in
    执行语句
    }
        // 正常写法
loadData ({ () -> () in
print("执行了")
})
*/ /*
// 闭包的其它写法
// 1.如果闭包是函数的最后一个参数, 那么可以把闭包写在调用函数的()后面
// 这种写法, 我们称之为 "尾随闭包"
loadData("123") {
() -> ()
in
print("执行了")
} // 2.如果函数只接收一个参数, 并且这个参数是闭包, 那么调用函数的()可以省略
// 这种写法, 我们称之为 "尾随闭包"
loadData {
() -> ()
in
print("执行了")
}
func loadData(since_id: String, finished: ()->()) -> Void {
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print("子线程做耗时操作 \(NSThread.currentThread())") dispatch_async(dispatch_get_main_queue(), { () -> Void in
print("主线程更新UI \(NSThread.currentThread())")
finished()
})
}
} /*
func loadData(finished: ()->()) -> Void {
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print("子线程做耗时操作 \(NSThread.currentThread())") dispatch_async(dispatch_get_main_queue(), { () -> Void in
print("主线程更新UI \(NSThread.currentThread())")
finished()
})
}
}

闭包的循环引用

  • 闭包循环强引用
  • block

    • 闭包和block很像, 都是提前准备好代码, 在需要时执行
    • block会对外部变量进行强引用, 保证执行代码时变量还在
    • block中用到self一定要非常小心 闭包
    • 闭包也一样, 会对外部变量进行强引用, 保证执行代码时变量还在
    • 如果您将闭包赋值给一个类实例的属性,并且该闭包通过访问该实例或其成员而捕获了该实例,您将创建一个在闭包和该实例间的循环强引用
    • Swift开发中能不写self就不写self, 一看到self就想到闭包
  • OC中如何解决循环引用

    • __weak typeof(self) weakSelf = self;
    • 特点: 对象释放后会自动将变量赋值为nil
    • __unsafe_unretained typeof(self) weakSelf = self;
    • 特点: 对象释放后不会自动将变量赋值为nil, 指向一块废弃的存储空间
  • Swift中如何解决循环引用

    • weak var weakSelf = self
    • weak 相当于OC中的 __weak, 和OC一样 对象释放后会自动将变量赋值为nil
    • 所以被weak修饰的变量是可选类型

    • unowned var weakSelf = self

    • unowned 相当于OC中的__unsafe_unretained, 和OC一样, 对象释放后不会自动将变量赋值为nil
    • 所以被unowned修饰的变量, 不是可选类型

      注意: weak和unowned只能修饰对象类型, 因为只有对象类型才有引用计数

  • 应用场景:

    • 什么时候用weak

      • 当被保存的对象有可能提前释放时就用weak
    • 什么时候用unowned
      • 当被保存的对象在使用时不会被提前释放时就用unowned
  • 捕获列表

    • 可以在调用闭包时在形参列表前面通过[]指定捕获列表, 告诉系统如何处理指定的这些值
        //weak var weakSelf = self
//unowned var weakSelf = self callBack = { [unowned self ,weak btn = self.button] () -> () in
//self.view.backgroundColor = UIColor.redColor()
//weakSelf.view.backgroundColor = UIColor.redColor()
self.view.backgroundColor = UIColor.redColor()
print(btn)
} loadData(callBack!)
} func loadData(finished: ()->()) -> Void { dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print("子线程做耗时操作 \(NSThread.currentThread())") dispatch_async(dispatch_get_main_queue(), { () -> Void in
print("主线程更新UI \(NSThread.currentThread())")
finished()
})
}
}
  • 析构函数

    • 析构器只适用于类类型,当一个类的实例被释放之前,析构器会被立即调用
    • 类似于OC中的dealloc方法
    • 析构器是在实例释放发生前被自动调用。你不能主动调用析构器
    • 一般情况下, 当使用自己的资源时, 在析构函数中进行一些额外的清理
    • 例如,如果创建了一个自定义的类来打开一个文件,并写入一些数据,你可能需要在类实例被释放之前手动去关闭该文件

deinit {
print("88")
}

End

Swift语法基础入门三(函数, 闭包)的更多相关文章

  1. Swift语法基础入门四(构造函数, 懒加载)

    Swift语法基础入门四(构造函数, 懒加载) 存储属性 具备存储功能, 和OC中普通属性一样 // Swfit要求我们在创建对象时必须给所有的属性初始化 // 如果没办法保证在构造方法中初始化属性, ...

  2. Swift语法基础入门二(数组, 字典, 字符串)

    Swift语法基础入门二(数组, 字典, 字符串) 数组(有序数据的集) *格式 : [] / Int / Array() let 不可变数组 var 可变数组 注意: 不需要改变集合的时候创建不可变 ...

  3. Swift语法基础入门一(适合有C, OC开发人员)

    Swift开发体验 /*: 创建对象 * OC: alloc initWithXXX 方法 * Swift: (xxx:) */ /*: 调用方法 * OC: [UIColor redColor]; ...

  4. C#基础入门 三

    C#基础入门 三 类 类使用class关键字进行声明,前面加一个访问修饰符,public class car{} 访问修饰符:修师傅可以用来修饰类和类成员等,控制它们的可见度 修饰符关键字分别为:pu ...

  5. Java04-Java语法基础(三)流程控制

    Java04-Java语法基础(三)流程控制 一.数据类型的转换 1.自动转换:在赋值运算中,占字节数大的类型会自动向字节小的类型转换 double d1 = 3.14; int t1 = d1; 2 ...

  6. js语法基础入门(1)

    1.基础入门 1.1.hello world 1.1.1.JavaScript是什么? JavaScript是一门跨平台.面向对象的轻量级脚本语言,在web开发中被广泛应用 1.1.2.JavaScr ...

  7. python3 入门 (三) 函数与lambda表达式、闭包

    函数 是组织好的.可重复使用的.用来实现单一或相关联功能的代码段. 函数代码块以def关键词开头,后接函数标识符名称和圆括号() 任何传入参数和自变量必须放在圆括号中间.圆括号之间可以用于定义参数 函 ...

  8. python基础(三)闭包与装饰器

    闭包(closure): 内嵌函数通过调用外部嵌套函数作用域内的变量,则这个内嵌函数就是闭包. 闭包必须满足三个条件: 必须有一个内嵌函数 内嵌函数必须引用外部嵌套函数中的变量 外部函数的返回值必须是 ...

  9. js语法基础入门(7)

    7.数组 7.1.什么是数组以及相关概念? 什么是数组?是一组数据有序排列的集合.将一组数据按一定顺序组织为一个组合,并对这个组合命名,这样便构成了数组. 什么是数组元素?组成数组的每一个数据称为数组 ...

随机推荐

  1. System.Speech.Synthesis 添加暂停、继续功能

    为了方便调用暂停.继续的方法.要将speech的功能写成一个类.直接附上代码: using System; using System.Collections.Generic; using System ...

  2. Windows I/O模型之一:Select模型

    1.概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock) 四种调用模式: 同步:所谓同步,就是在发出一个功能调用时,在没有得到结果 ...

  3. Linux安装系统注意事项及系统初始化

      Linux安装系统注意事项 1.分区 学习用途: /boot:200M /swap :内存的1到2倍 /:根据需要分配大小,比如虚拟机下总空间是15G,那么可以分配8——10G跟/分区,如果是生产 ...

  4. PHP PSR-2 代码风格规范 (中文版)

    代码风格规范 本篇规范是 PSR-1 基本代码规范的继承与扩展. 本规范希望通过制定一系列规范化PHP代码的规则,以减少在浏览不同作者的代码时,因代码风格的不同而造成不便. 当多名程序员在多个项目中合 ...

  5. Dividing (hdu 1059 多重背包)

    Dividing Sample Input 1 0 1 2 0 0 价值为1,2,3,4,5,6的物品数目分别为 1 0 1 2 0 0,求能否将这些物品按价值分为两堆,转化为多重背包.1 0 0 0 ...

  6. “弹出DVD驱动器错误”解决方法

    错误描述:(win7环境) 买了个开发板,赠送了一些光盘,放在电脑光驱中打开后,电脑就疯狂响,可能是光盘质量太差.用完后在弹出时显示“弹出DVD驱动器错误”[见图1].直接按主机上弹出按钮也没有反应. ...

  7. linux开启mysql远程登录

    Mysql默认root用户只能本地访问,不能远程连接管理mysql数据库,Linux如何开启mysql远程连接?设置步骤如下:1.GRANT命令创建远程连接mysql授权用户itloggermysql ...

  8. 关于在Reshaper中添加代码模板代码段

    http://www.cnblogs.com/tristinjet/archive/2009/08/19/1550203.html 去 tools->模板中进行模板编辑设置

  9. Linux系统编程(24)——信号的生命周期

    信号生命周期为从信号发送到信号处理函数的执行完毕. 对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完毕)来说,可以分为三个重要的阶段,这三个阶段由四个重要事件来刻画:信号诞生:信号在进程中 ...

  10. hdu 2202 最大三角形_凸包模板

    题意:略 思路:直接套用凸包模板 #include <iostream> #include <cstdio> #include <cmath> #include & ...