函数

目标

  • 掌握函数的定义
  • 掌握外部参数的用处
  • 掌握无返回类型的三种函数定义方式

代码实现

  • 函数的定义

    • 格式 func 函数名(行参列表) -> 返回值 {代码实现}
    • 调用 let result = 函数名(值1, 参数2: 值2...)
func sum(a: Int, b: Int) -> Int {
return a + b
} let result = sum(10, b: 20)
  • 没有返回值的函数,一共有三种写法

    • 省略
    • ()
    • Void
func demo(str: String) -> Void {
print(str)
}
func demo1(str: String) -> () {
print(str)
}
func demo2(str: String) {
print(str)
} demo("hello")
demo1("hello world")
demo2("olleh")
  • 外部参数

    • 在形参名前再增加一个外部参数名,能够方便调用人员更好地理解函数的语义
    • 格式:func 函数名(外部参数名 形式参数名: 形式参数类型) -> 返回值类型 { // 代码实现 }
    • Swift 2.0 中,默认第一个参数名省略
func sum1(num1 a: Int, num2 b: Int) -> Int {
return a + b
} sum1(num1: 10, num2: 20)

闭包

与 OC 中的 Block 类似,闭包主要用于异步操作执行完成后的代码回调,网络访问结果以参数的形式传递给调用方

目标

  • 掌握闭包的定义
  • 掌握闭包的概念和用法
  • 了解尾随闭包的写法
  • 掌握解除循环引用的方法

闭包的定义

  • 定义一个函数
//: 定义一个 sum 函数
func sum(num1 num1: Int, num2: Int) -> Int {
return num1 + num2
}
sum(num1: 10, num2: 30) //: 在 Swift 中函数本身就可以当作参数被定义和传递
let mySum = sum
let result = mySum(num1: 20, num2: 30)
  • 定义一个闭包

    • 闭包 = { (行参) -> 返回值 in // 代码实现 }
    • in 用于区分函数定义和代码实现
//: 闭包 = { (行参) -> 返回值 in // 代码实现 }
let sumFunc = { (num1 x: Int, num2 y: Int) -> Int in
return x + y
}
sumFunc(num1: 10, num2: 20)
  • 最简单的闭包,如果没有参数/返回值,则 参数/返回值/in 统统都可以省略

    • { 代码实现 }
let demoFunc = {
print("hello")
}

基本使用

GCD 异步

  • 模拟在后台线程加载数据
func loadData() {
dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in
print("耗时操作 \(NSThread .currentThread())")
})
}
  • 尾随闭包,如果闭包是最后一个参数,可以用以下写法
  • 注意上下两段代码,} 的位置
func loadData() {
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print("耗时操作 \(NSThread .currentThread())")
}
}
  • 闭包的简写,如果闭包中没有参数和返回值,可以省略
func loadData() {
dispatch_async(dispatch_get_global_queue(0, 0)) {
print("耗时操作 \(NSThread .currentThread())")
}
}

自定义闭包参数,实现主线程回调

  • 添加没有参数,没有返回值的闭包
override func viewDidLoad() {
super.viewDidLoad() loadData {
print("完成回调")
}
} // MARK: - 自定义闭包参数
func loadData(finished: ()->()) { dispatch_async(dispatch_get_global_queue(0, 0)) {
print("耗时操作 \(NSThread.currentThread())") dispatch_sync(dispatch_get_main_queue()) {
print("主线程回调 \(NSThread.currentThread())") // 执行回调
finished()
}
}
}
  • 添加回调参数
override func viewDidLoad() {
super.viewDidLoad() loadData4 { (html) -> () in
print(html)
}
} /// 加载数据
/// 完成回调 - 传入回调闭包,接收异步执行的结果
func loadData4(finished: (html: String) -> ()) { dispatch_async(dispatch_get_global_queue(0, 0)) {
print("加载数据 \(NSThread.currentThread())") dispatch_sync(dispatch_get_main_queue()) {
print("完成回调 \(NSThread.currentThread())") finished(html: "<h1>hello world</h1>")
}
}
}

循环引用

  • 建立 NetworkTools 对象
class NetworkTools: NSObject {

    /// 加载数据
///
/// - parameter finished: 完成回调
func loadData(finished: () -> ()) {
print("开始加载数据...") // ...
finished()
} deinit {
print("网络工具 88")
}
}
  • 实例化 NetworkTools 并且加载数据
class ViewController: UIViewController {

    var tools: NetworkTools?

    override func viewDidLoad() {
super.viewDidLoad() tools = NetworkTools()
tools?.loadData() {
print("come here \(self.view)")
}
} /// 与 OC 中的 dealloc 类似,注意此函数没有()
deinit {
print("控制器 88")
}
}

运行不会形成循环引用,因为 loadData 执行完毕后,就会释放对 self 的引用

  • 修改 NetworkTools,定义回调闭包属性
/// 完成回调属性
var finishedCallBack: (()->())? /// 加载数据
///
/// - parameter finished: 完成回调
func loadData(finished: () -> ()) { self.finishedCallBack = finished print("开始加载数据...") // ...
working()
} func working() {
finishedCallBack?()
} deinit {
print("网络工具 88")
}

运行测试,会出现循环引用

解除循环引用

  • 与 OC 类似的方法
/// 类似于 OC 的解除引用
func demo() {
weak var weakSelf = self
tools?.loadData() {
print("\(weakSelf?.view)")
}
}
  • Swift 推荐的方法
loadData { [weak self] in
print("\(self?.view)")
}
  • 还可以
loadData { [unowned self] in
print("\(self.view)")
}

闭包(Block) 的循环引用小结

  • Swift

    • [weak self]

      • self是可选项,如果self已经被释放,则为nil
    • [unowned self]
      • self不是可选项,如果self已经被释放,则出现野指针访问
  • Objc

    • __weak typeof(self) weakSelf;

      • 如果self已经被释放,则为nil
    • __unsafe_unretained typeof(self) weakSelf;
      • 如果self已经被释放,则出现野指针访问

Swift 入门之简单语法(四)的更多相关文章

  1. Swift 入门之简单语法(六)

    KVC 字典转模型构造函数 /// `重写`构造函数 /// /// - parameter dict: 字典 /// /// - returns: Person 对象 init(dict: [Str ...

  2. Swift 入门之简单语法(二)

    可选项判断 由于可选项的内容可能为 nil,而一旦为 nil 则不允许参与计算 因此使用中,经常需要判断可选项的内容是否为 nil 单个可选项判断 let url = NSURL(string: &q ...

  3. Swift 入门之简单语法(一)

    定义 let 定义常量,一经赋值不允许再修改 var 定义变量,赋值之后仍然可以修改 //: # 常量 //: 定义常量并且直接设置数值 let x = 20 //: 常量数值一经设置,不能修改,以下 ...

  4. Swift 入门之简单语法(五)

    面向对象 目标 构造函数 构造函数的基本概念 构造函数的执行顺序 KVC 在构造函数中的使用及原理 便利构造函数 析构函数 区分 重载 和 重写 懒加载 只读属性(计算型属性) 设置模型数据(didS ...

  5. Swift 入门之简单语法(三)

    集合 数组 数组使用 [] 定义,这一点与 OC 相同 //: [Int] let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 遍历 for num in nu ...

  6. Swift入门教程:基本语法(四)

    可选类型 可选类型的使用场合 当一个值可能存在,可能不存在的时候,就用可选类型 比如查找字符k在某个字符串中的位置 如果字符串是"jake",说明k的位置存在,是2 如果字符串是& ...

  7. Swift入门教程:基本语法大全

    原文:Swift入门教程:基本语法大全       简介:                                                                        ...

  8. Swift入门教程:基本语法(一)

          简介:                                                                                       什么是S ...

  9. swift入门-day01-基本语法

    主要内容: 1.常量和变量 2.Optional 3.控制流 4.循环 5.字符串 6.集合 变量和常量 定义 let 定义常量,一经赋值不允许再修改 var 定义变量,赋值之后仍然可以修改 自动推导 ...

随机推荐

  1. Ubuntu 12.4 server 安装 redmine

    1,安装默认的redmine apt-get install apache2 libapache2-mod-passenger mysql-server redmine redmine-mysql 直 ...

  2. MAT(Memory Analyzer Tool)使用心得

    起因:最近在跟踪产品的性能问题,期间主要问题体现在JVM的内存回收问题,使用MAT工具进行JVM内存分析(也可对android 的应用内存分析) 问题描述: 1.部分后端服务在运行一段时间后会突然年老 ...

  3. RabbitMQ-从基础到实战(6)— 与Spring集成

    0.目录 RabbitMQ-从基础到实战(1)- Hello RabbitMQ RabbitMQ-从基础到实战(2)- 防止消息丢失 RabbitMQ-从基础到实战(3)- 消息的交换(上) Rabb ...

  4. mysql常用技能分享

    一,MySQL查询的五种子句: 1,where(条件查询),常用的运算符: ①比较运算符 > , < , = , != , >= , <= , in( ) , between ...

  5. 关于MYSQL存储中文问题

    最近在学习MYSQL时遇到了不能存储中文的问题,在网上找了很多类似的方法,最后都失败了(失败原因:修改完my.cnf文件后mysql server重新启动失败),濒临崩溃的时候重装了下mysql(Ub ...

  6. key-value存储Redis

    Key-value数据库是一种以键值对存储数据的一种数据库,(类似java中的HashMap)每个键都会对应一个唯一的值. Redis与其他 key - value 数据库相比还有如下特点: Redi ...

  7. androidStudio通过svn进行版本控制

    andoridStudio配置使用svn(以windows为例) 1.先安装svn客户端程序,TortoiseSVN,注意安装过程中要勾选command line client tools(默认是不安 ...

  8. list、set、map区别

    list是有序且重复的; list中的数据都是按照写入的顺序排列的,存入list的数据用add方法写入; list可以用循环遍历list以达到获取全部数据的目的,同时也可以通过下标get(index) ...

  9. Angular2.js——表单(上)

    表单创建一个有效.引人注目的数据输入体验.Angular表单协调一组数据绑定控件,跟踪变更.验证输入的有效性,并且显示错误信息. 接下来,主要内容有: 1.使用组件和模板构建Angular表单: 2. ...

  10. 蓝桥杯-猜年龄-java

    /* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...