本文主要介绍Swift的闭包的使用并与OC的Block做比较。学习Swift是绕不过闭包的,因为无论是全局函数还是嵌套函数都是闭包的一种,本文主要介绍闭包表达式。

1.闭包表达式的使用

        // 1.定义一个闭包
let myClosure = {
(s1: String, s2:String) -> Bool
in
self.count = 10;
print("------");
return s1 > s2
}
print(count!);
// 2.调用闭包
let result = myClosure("Chris","Alex")
print("result = \(result)")
print("count = \(count!)")

日志

result = true
count = 10

总结 :1.和oc的block的声明和调用在形式上是极其类似的,不过闭包可以直接修改局部变量和全局变量的值,而block需要__block 关键字。

       // 3.Tralling 闭包(尾随)
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
( number) -> String in
var number = number
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
print(strings);

日志

["OneSix", "FiveEight", "FiveOneZero"]

2.Trailing 闭包

  函数的表现形式:(void)函数名(参数)。如果一个函数的最后一个参数是一个闭包,允许你写在参数所在哪个()外面。

(void)函数名(参数) {

};

如果只有闭包一个参数,括号可以省略。变成:

(void)函数名 {

};

当闭包里的代码很多的时候,这样写可以增加代码的可读性,多用于调用系统的函数。

  举例之前先介绍一下map函数,map属于Array的一个函数,调用这个函数需要传入一个闭包,返回一个新数组。Array里的每一个元素都会调用这个闭包,生成一个新对象,加入到新数组中。相当于 自动执行了for in和addobject两个方法,很实用。

let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]

使用Trailing 闭包之前

let strings = numbers.map({
( number) -> String in
var number = number
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
})

使用Trailing 闭包之后

let strings = numbers.map{
( number) -> String in
var number = number
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}

  就一个参数不明显, 但是参数多了还是很有用的。因为闭包里的代码一般有很多,会导致包含参数的()距离太远。

3. 捕获: 解决嵌套函数的循环引用

func makeIncrementor(forIncrement amount: Int) -> () -> Int {

            var runningTotal = 0
func incrementor() -> Int {
// 只能捕获包含他的函数体内的变量或常量的值,建立一个副本,相当于深拷贝
// 新变量
runningTotal += amount
return runningTotal
}
print(" ----- runningTotal = \(runningTotal)")
return incrementor
} let incrementByTen = makeIncrementor(forIncrement: 10)
print("incrementor = \(incrementByTen())")
print("incrementor = \(incrementByTen())")
print("incrementor = \(incrementByTen())")

打印

 ----- runningTotal = 0
incrementor = 10
incrementor = 20
incrementor = 30

总结:incrementor的runningTotal就是对:incrementor的runningTotal的捕获。捕获有以下几个特点。

(1)捕获会生成一个新变量,和捕获变量的值相等,但内存不同,是引用类型,相当于OC中的深拷贝,新变量变化和捕获的变量没有任何关系了。因为incrementor的runningTotal的值一直没有改变。

(2)嵌套函数对新变量是强引用,只要嵌套函数还在,新变量就在,因为incrementor的返回值是一直增加的。

(3)如果不这样为什么会造成循环引用,incrementor对makeIncrementor变量runningTotal的引用就是对makeIncrementor的引用。运用捕获,就只是对runningTotal值的拷贝,不引用。

4.闭包传值

  在OC中我们用block最多的地方就是传值了,同样闭包也是。不过运用block和闭包传值最好是当对象只有一个状态的时候,如果对象状态很多最好用代理。

CycleScrollView 往CycleScrollViewViewController进行传值

import UIKit

// 定义闭包类型
typealias DidSelectItemClosureType = (Int) -> Void
class CycleScrollView: UIView, UICollectionViewDelegate,UICollectionViewDataSource {
// Mark:UICollectionViewDelegate
// 点击方法
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { if self.didSelectItemClosure != nil {
// 13.利用闭包传值
self.didSelectItemClosure!(indexPath.row == 3 ? 0 : indexPath.row);
}
}
}

接收闭包传过来的值

import UIKit

class CycleScrollViewViewController: UIViewController {

    var cycleScrollView : CycleScrollView?
override func viewDidLoad() {
super.viewDidLoad()
createUI()
}
func createUI() { self.automaticallyAdjustsScrollViewInsets = false; cycleScrollView = CycleScrollView.init(frame: CGRect(x:0,y:64,width:ScreenWidth,height:ScreenHeight - 64))
// 闭包传值
cycleScrollView?.didSelectItemClosure = {
(index : Int) -> Void in print("您点击了第 \(index) 个")
}
self.view.addSubview(cycleScrollView!)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning() }
}

  如果传值的例子有点没看懂,可以去下载我的DEMO,里面有详细的代码。闭包还是很厉害的,不需要我们进行任何操作就解决了循环引用问题,不像block还得对变量进行弱引用。本文部分内容是对Swift闭包详解的整理。

Swift应用案例 2.闭包入门到精通的更多相关文章

  1. (升级版)Spark从入门到精通(Scala编程、案例实战、高级特性、Spark内核源码剖析、Hadoop高端)

    本课程主要讲解目前大数据领域最热门.最火爆.最有前景的技术——Spark.在本课程中,会从浅入深,基于大量案例实战,深度剖析和讲解Spark,并且会包含完全从企业真实复杂业务需求中抽取出的案例实战.课 ...

  2. Swift从入门到精通第十一篇 - 初始化 初识

    初始化(学习笔记) 环境Xcode 11.0 beta4 swift 5.1 初始化 初始化是类.结构体.枚举生成实例的过程,为该类的每个存储属性设置初始值,有些在实例使用前的设置或初始化也可在此实现 ...

  3. Swift从入门到精通第八篇 - 方法 初识

    方法(学习笔记) 环境Xcode 11.0 beta4 swift 5.1 方法 结构体.枚举.类都可以定义方法(实例方法.类型方法) 实例方法(Instance Methods) 实例方法只能用实例 ...

  4. redis入门到精通系列(二):redis操作的两个实践案例

    在前面一篇博客中我们已经学完了redis的五种数据类型操作,回顾一下,五种操作类型分别为:字符串类型(string).列表类型(list).散列类型(hash).集合类型(set).有序集合类型(so ...

  5. 《JAVA 从入门到精通》 - 正式走向JAVA项目开发的路

    以前很多时候会开玩笑,说什么,三天学会PHP,七天精通Nodejs,xx天学会xx ... 一般来说,这样子说的多半都带有一点讽刺的意味,我也基本上从不相信什么快速入门.我以前在学校的时候自觉过很多门 ...

  6. iOS回顾笔记(06) -- AutoLayout从入门到精通

    iOS回顾笔记(06) -- AutoLayout从入门到精通 随着iOS设备屏幕尺寸的增多,当下无论是纯代码开发还是Xib/StoryBoard开发,自动布局已经是必备的开发技能了. 我使用自动布局 ...

  7. 【PHP】最详细PHP从入门到精通(二)——PHP中的函数

     PHP从入门到精通 之PHP中的函数 各位开发者朋友大家好,自上次更新PHP的相关知识,得到了大家的广泛支持.PHP的火爆程度不言而喻,函数作为PHP中极为重要的部分,应诸位的支持,博主继续跟进更新 ...

  8. 2017最新技术java高级架构、千万高并发、分布式集群、架构师入门到精通视频教程

    * { font-family: "Microsoft YaHei" !important } h1 { color: #FF0 } 15套java架构师.集群.高可用.高可扩展. ...

  9. Javascript闭包入门(译文)

    前言 总括 :这篇文章使用有效的javascript代码向程序员们解释了闭包,大牛和功能型程序员请自行忽略. 译者 :文章写在2006年,可直到翻译的21小时之前作者还在完善这篇文章,在Stackov ...

随机推荐

  1. Python 接口测试(一)

    @font-face { font-family: "Times"; }@font-face { font-family: "宋体"; }@font-face ...

  2. jQuery插件,将内容插入到光标处

    (function ($) { $.fn.extend({ insertAtCaret : function (myValue) { var $t = $(this)[0]; if (document ...

  3. Markdown 标记语言简介

    简介 做为一种标记语言,广泛应用在写作领域,markdown语法编写的文本,经过特殊的软件进行展示: 目的:相对html,markdown提高文本的可读可写性 兼容:兼容html 自动转换特殊字符:& ...

  4. php中的实用分页类

    <table width="100%" border="1" cellpadding="0" cellspacing="0& ...

  5. YoMail 邮箱客户端的社会化之路,起于邮箱,不止于邮件

    你还记不记得上一次用邮箱处理私人事务是什么时候?从什么时候开始邮箱于你而言,唯一功能沦为了收取各种网站的验证信息? 电子邮件实际上非常适合于工作上使用,比起其他通信工具,或者社会化媒体,电子邮件在工作 ...

  6. mysql忘掉密码

    1. 先杀掉mysqld的进程: service mysql stop 2. 使用skip-grant-tables这个选项启动MySQL: vi /etc/my.cnf 在mysqld 下添加 sk ...

  7. java读取文件方法总结

    由于最近在做一个关于从手机本地读取格式化的txt文件中的内容,并且把内容放在listview中显示.这样问题来了,就是如何能够遍历已经获取到特定的map中就是一个问题,在网上找了一些资料,找到了一个很 ...

  8. ES6-01:常量与变量的声明

    首先,我们声明一个变量: //定义一个变量num,并赋值为10: let num = 10; //进行打印 console.log(num); let与var有所不同: 语法特点1:let变量只能在当 ...

  9. iOS回顾笔记(04) -- UIScrollView的基本使用详解

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  10. C++设计模式:Template Method

    我使用过一个简单的后台服务框架.这个框架上手很容易,我只需要继承一个基类,同时实现,或重写(override)基类声明的几个接口(这些接口声明为虚函数,或者纯虚函数),然后调用基类定义好的run()函 ...