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

函数:

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

没有参数没有返回值

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

有参数没有返回值

内部/外部参数

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

默认参数(Default Parameter Values)

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

注意

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

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

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

注意

  • 对变量参数所进行的修改在函数调用结束后便消失了,并且对于函数体外是不可见的。变量参数仅仅存在于函数调用的生命周期中
  1. func sum4(let i: Int, let j: Int) {
  2. print(i + j)
  3. }
  4. sum4(10, j: 20)
  5. var num1 = 10
  6. var num2 = 20
  7. //func swap(value1: Int, value2: Int){
  8. // let temp = value1
  9. // value1 = value2
  10. // value2 = temp
  11. //}
  12. // 注意: 操作的是局部变量, 对实参没有影响
  13. func swap1(var value1: Int, var value2: Int){
  14. print("交互前: value1 = \(value1), value2 = \(value2)")
  15. let temp = value1
  16. value1 = value2
  17. value2 = temp
  18. print("交互后: value1 = \(value1), value2 = \(value2)")
  19. }
  20. swap1(num1, value2: num2)
  21. print(num1)
  22. print(num2)

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

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

注意

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

可变参数(Variadic Parameters)

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

注意

  • 一个函数最多只能有一个可变参数
  • 变参只能是同种类型的数据
  • 变参必须指定数据类型
  • 如果函数有一个或多个带默认值的参数,而且还有一个可变参数,那么把可变参数放在参数表的最后
  1. func sum5(numbers: Int...) {
  2. // print(numbers)
  3. var sum = 0
  4. for number in numbers {
  5. sum += number
  6. }
  7. print(sum)
  8. }
  9. sum5(1, 2, 3)
  10. // 不推荐写法, 和默认值一样, 变参最好写在最后
  11. func sum6(numbers: Int..., var sum: Int) {
  12. // print(numbers)
  13. for number in numbers {
  14. sum += number
  15. }
  16. print(sum)
  17. }
  18. sum6(1, 2, 3, sum: 0)
  19. // 推荐写法
  20. func sum7(var sum: Int = 100, numbers: Int...) {
  21. // print(numbers)
  22. for number in numbers {
  23. sum += number
  24. }
  25. print(sum)
  26. }
  27. sum7(numbers: 1, 2, 3)
  28. // 一个函数中只能有一个变参
  29. //func sum8(numbers: Int..., values: Int...){
  30. // print(numbers)
  31. // print(values)
  32. //}
  33. // 有参数有返回值
  34. func sum8(i: Int, j: Int) -> Int {
  35. return i + j
  36. }
  37. let result = sum8(10, j: 20)
  38. print(result)

闭包

闭包

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

闭包的循环引用

  • 闭包循环强引用
  • 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
  • 捕获列表

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

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

  1. deinit {
  2. print("88")
  3. }

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. Glide的加载图片的帮助类,用来把图片圆角或者改成圆形图片

    Glide虽然非常好用但是没找到把图片圆角的方法,所以百度了一个非常不错的加载类自己实现圆角图 感谢原文章作者:http://blog.csdn.net/weidongjian/article/det ...

  2. React-Native做一个文本输入框组件

    我又回来啦! 由于最近一直在做公司的项目,而且比较急.如今项目已经迭代到第三期,可以缓一缓了... 说实话,最近一直再用android做开发,而且时间也不宽裕,react-native有点生疏了. 好 ...

  3. Request获取url各种信息的方法

    1.Request获取url各种信息的方法 测试的url地址:http://www.test.com/testweb/default.aspx, 结果如下: Request.ApplicationPa ...

  4. [uva11916] Emoogle Grid (离散对数)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud  Emoogle Grid  You have to color an MxN ( ...

  5. Draw2d中的布局管理器Layout比较

    最近在研究Eclipse中的GEF开发,在跟着GEF-whole-upload教程做一个GEF应用程序的例子时,发现Figure上的控件无法显示,谷歌了很久也没找到解决方案,最后终于发现是Layout ...

  6. Python爬虫学习:四、headers和data的获取

    之前在学习爬虫时,偶尔会遇到一些问题是有些网站需要登录后才能爬取内容,有的网站会识别是否是由浏览器发出的请求. 一.headers的获取 就以博客园的首页为例:http://www.cnblogs.c ...

  7. 转:linux运维工程师

    运维中关键技术点解剖:1 大量高并发网站的设计方案:2 高可靠.高可伸缩性网络架构设计:3 网站安全问题,如何避免被黑?4 南北互联问题,动态CDN解决方案:5 海量数据存储架构 一.什么是大型网站运 ...

  8. 【1】python核心编程 第三章

    1.继续( \ ) 有两种例外情况一个语句不使用反斜线也可以跨行.在使用闭合操作符时,单一语句可以跨多行,例如:在含有小括号.中括号.花括号时可以多行书写.另外就是三引号包括下的字符串也可以跨行书写 ...

  9. RenderPartial RenderAction Partial Action

    MVC Razor中有不同的展现partial view的方法,许多开发人员子在选择使用 RenderPartial or RenderAction or Partial or Action help ...

  10. 使用PHP从web访问mysql数据库

    一. web数据库构架的工作原理 1. 用户由浏览器发出HTTP请求,请求特定的web页面. 2. web服务器接受接收到对特定页面的请求,检索相应文件,并将其传递给php引擎处理. 3. php引擎 ...