Swift应用案例 2.闭包入门到精通

  本文主要介绍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值的拷贝,不引用。

循环引用.png

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闭包详解的整理。

posted @ 2017-03-27 13:37  豆丶浆油条  阅读(336)  评论(0编辑  收藏  举报