swift 中的闭包_swift 如何不让闭包自动转为尾随闭包 - CSDN
  • Swift4.0闭包 (重要)

    2017-10-18 18:41:06
    2 从单行表达式闭包中隐式返回 可以省略return 3 可以使用简化的参数如 $0 $1 意为从0或者1开始 4 提供了尾随闭包的语法 */ //语法 parameters参数 return 隐藏了 //{(parameters) -> return type in // paramet
    /*
    Swift 中的闭包有很多优化的地方
    1 根据上下文推断参数和返回值的类型
    2 从单行表达式闭包中隐式返回 可以省略return
    3 可以使用简化的参数如 $0 $1 意为从0或者1开始
    4 提供了尾随闭包的语法
    */
    //语法   parameters参数 return 隐藏了
    //{(parameters) -> return type in
    //    parameters
    //}
    //最简单的闭包//省略in的
    let b = {
        print("这也是闭包")
    }

    //用变量记录函数 (带参数的闭包)
    //带有参数的闭包
    //参数返回值 实现代码  {形参->返回值 in 代码}
    //带参数待返回值的闭包
    let countNum = {(num1:Int,num2:Int)->Int in
        return num1+num2;
    }
    let count1 = countNum(2,3)


    //闭包的应用场景

    /*异步执行完成回调  控制器之间的回调  自定义视图的回调*/

    /*  以下代码需要在项目中的.Swift文件中完成
    override func viewDidLoad() {
    super.viewDidLoad()
    loadData { (result) in
    print("获取json信息\(result)")
    }
    // Do any additional setup after loading the view, typically from a nib.
    }
    func loadData(completion: @escaping (_ result: [String])->()) -> () {
    DispatchQueue.global().async {
    print("耗时操作\(Thread.current)")
    Thread.sleep(forTimeInterval: 1.0);
    let json=["12","23","34"]
    DispatchQueue.main.async(execute: {
    print("主线程\(Thread.current)")
    completion(json)
    })
    }
    }
    结果为:耗时操作<NSThread: 0x600000277000>{number = 3, name = (null)}
    主线程<NSThread: 0x604000075a80>{number = 1, name = main}
    获取json信息["12", "23", "34"]
    */

    //闭包表达式
    let names = ["s","b","e","h","f"]

    func backwards(a1:String,a2:String)->Bool{
        return a1<a2;
    }
    // public func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]
    var result = names.sorted(by:backwards)
    print(result)

    //参数名缩写
    ///以上代码还可以  Swift自动内联函数提供了参数名称缩写功能,您可以直接通过$0,$1,$2来顺序调用闭包的参数。
    var result1 = names.sorted(by:{$0<$1})
    print(result1)

    //作为一个函数接受两个String类型的参数并返回Bool类型的值Swift可以自动推断出您想使用大于号的字符串函数实现:
    //运算符函数
    var result2 = names.sorted(by:<)
    print(result2)

    //尾随闭包
    //例子1  尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。

    var result3 = names.sorted(){$0<$1}
    print(result3)



    //例子2
    //此时点回车函数会变成中括号的形式 也就是说如果函数的最后一个参数是闭包,函数的参数可以提前结束
    //        最后一个参数直接使用{}来包装闭包的代码
    //        loadData1(completion: <#T##([String]) -> ()#>)
    //以下两段代码相同只不过一个是使用尾随闭包的写法
    /*func loadData(completion:@escaping (_ result:([String])->())->()){
        DispatchQueue.global().async {
            print("耗时操作\(Thread.current)")
            Thread.sleep(forTimeInterval: 1.0);
            let json=["12","23","34"]
            //以下两段代码相同只不过一个是使用尾随闭包的写法
            DispatchQueue.main.async{
                print("主线程\(Thread.current)")
                completion(json)
            }
            DispatchQueue.main.async(execute: {
                print("主线程\(Thread.current)")
                completion(json)
            })
            
        }
    }
    */


    良言一句三冬暖,恶语伤人六月寒。无论工作还是生活,都不要拿脾气当做与他人博弈的武器。即使侥幸一时赢了,最终也只是两败俱伤。一言一语间,完成的是沟通,体现的是修养。或许我们不能成为优秀的别人,却完全可以做更好的自己。
    展开全文
  • Swift中闭包的使用

    2019-07-01 21:57:55
    本文主要介绍Swift中闭包的使用:"闭包的定义"、"闭包的创建、赋值、调用"、"闭包常见的几种使用场景"和"使用闭包可能引起的循环强引用" 闭包的定义: 在Swift开发文档是这样介绍闭包的:闭包是可以在你的代码...

    本文主要介绍Swift中闭包的使用:"闭包的定义"、"闭包的创建、赋值、调用"、"闭包常见的几种使用场景"和"使用闭包可能引起的循环强引用

    闭包的定义:

    在Swift开发文档中是这样介绍闭包的:闭包是可以在你的代码中被传递和引用的功能性独立模块。Swift 中的闭包和 C 以及 Objective-C 中的 block 很像,还有其他语言中的匿名函数也类似。闭包的作用主要是:够捕获和存储定义在其上下文中的任何常量和变量的引用, 能够为你处理所有关于捕获的内存管理的操作。

    闭包的表达式语法:

    闭包表达式语法有如下的一般形式:

    { (参数) -> (返回值类型) in

     闭包中需要执行的代码

    }

    利用typealias为闭包类型定义别名

    typealias是Swift中用来为已经存在的类型重新定义名字的关键字(类似于OC语法中的 typedef),重新命名的新名字用来替代之前的类型,并且能够使代码变得更加清晰简单容易理解。

    typealias <type name> = <type expression>
    
    typealias Nothing = () -> ()或typealias Anything = () -> Void 定义一个无参无返回值的闭包
    
    typealias PrintNumber = (Int) -> ()
    
    typealias Add = (Int, Int) -> (Int)

    闭包的创建、赋值、调用

    闭包表达式语法能够使用常量形式参数、变量形式参数和输入输出形式参数,但不能提供默认值。可变形式参数也能使用,但需要在形式参数列表的最后面使用。元组也可被用来作为形式参数和返回类型。在闭包的中会用到一个关键字in,in 可以看做是一个分割符,他把该闭包的类型和闭包的函数体分开,in前面是该闭包的类型,in后面是具体闭包调用时保存的需要执行的代码。表示该闭包的形式参数类型和返回类型定义已经完成,并且闭包的函数体即将开始执行。

    方式一:利用typealias最完整的创建

    //为(_ num1: Int, _ num2: Int) -> (Int) 类型的闭包定义别名:Add
    
     typealias Add = (_ num1: Int, _ num2: Int) -> (Int)
    
    //创建一个 Add 类型的闭包常量:addCloser1
    
     let addCloser1: Add
    
    //为已经创建好的常量 addCloser1 赋值
    
     addCloser1 = {
    
      (_ num1: Int, _ num2: Int) -> (Int) in
    
      return num1 + num2
    
     }
    
    //调用闭包并接受返回值
    
     let result = addCloser1(20, 10)

    形式二:闭包类型申明和变量的创建合并在一起

    //创建一个 (_ num1: Int, _ num2: Int) -> (Int) 类型的闭包常量:addCloser1
    
     let addCloser1: (_ num1: Int, _ num2: Int) -> (Int)
    
    //为已经创建好的常量 addCloser1 赋值
    
     addCloser1 = {
    
       (_ num1: Int, _ num2: Int) -> (Int) in
    
       return num1 + num2
    
     }
    
     //调用闭包并接受返回值
    
     let result = addCloser1(20, 10)

    形式三:省略闭包接收的形参、省略闭包体中返回值

    //创建一个 (Int, Int) -> (Int) 类型的闭包常量:addCloser1
    
     let addCloser1: (Int, Int) -> (Int)
    
    //为已经创建好的常量 addCloser1 赋值
    
     addCloser1 = {
    
       (num1, num2) in
    
       return num1 + num2
    
     }
    
    //调用闭包并接受返回值
    
     let result = addCloser1(20, 10)

    形式四:在形式三的基础上进一步精简

    //创建一个 (Int, Int) -> (Int) 类型的闭包常量:addCloser1 并赋值
    
     let addCloser1: (Int, Int) -> (Int) = {
    
       (num1, num2) in
    
       return num1 + num2
    
      } 
    
    //调用闭包并接受返回值
    
     let result = addCloser1(20, 10)

    形式五:如果闭包没有接收参数省略in
     

    //创建一个 () -> (String) 类型的闭包常量:addCloser1 并赋值
    
      let addCloser1: () -> (String) = {
    
       return "这个闭包没有参数,但是有返回值"
    
       }
    
     //调用闭包并接受返回值
    
      let result = addCloser1()

    形式六:简写的实际参数名

    //创建一个 (String, String) -> (String) 类型的闭包常量:addCloser1 并赋值
    
      let addCloser1: (String, String) -> (String) = {
    
       return "闭包的返回值是:\($0),\($1)"
    
       }
    
     //调用闭包并接受返回值
    
      let result = addCloser1("Hello", "Swift!")

    说明: 得益于Swift的类型推断机制,我们在使用闭包的时候可以省略很多东西,而且Swift自动对行内闭包提供简写实际参数名,你也可以通过 $0, $1, $2 等名字来引用闭包的实际参数值。如果你在闭包表达式中使用这些简写实际参数名,那么你可以在闭包的实际参数列表中忽略对其的定义,并且简写实际参数名的数字和类型将会从期望的函数类型中推断出来。in关键字也能被省略,$0 和 $1 分别是闭包的第一个和第二个 String类型的 实际参数(引自文档翻译)

     

     

    闭包常见的几种使用场景

    场景一:利用闭包传值

    class ViewController: UIViewController {
    
        override func viewDidLoad() {
    
            super.viewDidLoad()
    
            view.backgroundColor = UIColor.white
    
            textF.isUserInteractionEnabled = false
    
        }
    
        @IBOutlet weak var textF: UITextField!
    
        
    
        @IBAction func buttonAction(_ sender: UIButton) {
    
            let twoVC = storyboard?.instantiateViewController(withIdentifier: "vc") as! TwoViewController
    
            twoVC.callBack = {
    
                self.textF.text = $0
    
            }
    
            self.navigationController?.pushViewController(twoVC, animated: true)
    
        }
    
    }
    
    
    
    
    import UIKit
    
    
    
    typealias CallBack = (_ str: String) -> ()
    
    
    
    class TwoViewController: UIViewController {
    
        
    
        var callBack: CallBack?
    
    
    
        override func viewDidLoad() {
    
            super.viewDidLoad()
    
            view.backgroundColor = UIColor.white
    
            self.title = "第二个页面"
    
        }
    
    
    
        @IBOutlet weak var textF: UITextField!
    
        override func viewWillDisappear(_ animated: Bool) {
    
            if let callBack = callBack {
    
                 callBack(textF.text ?? "")
    
            }
    
        }
    
    }

    把第二个页面的值传回到第一个页面

    场景二:闭包作为函数的参数

    一、尾随闭包

    如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。在使用尾随闭包时,你不用写出它的参数标签:

    func someFunctionThatTakesAClosure(closure: () -> Void) {
        // 函数体部分
    }
    
    
    
    // 以下是不使用尾随闭包进行函数调用
    someFunctionThatTakesAClosure(closure: {
        // 闭包主体部分
    })
    
    
    
    // 以下是使用尾随闭包进行函数调
    someFunctionThatTakesAClosure() {
        // 闭包主体部分
    }
    
    
    func combine(handle:(String, String) -> ()) {
            handle("111", "222")
        }
    
    
        @IBAction func buttonAction(_ sender: UIButton) {
    
    //        combine { (str1, str2) in
    
    //            print("hello   " + str1 + "  " + str2)
    
    //        }
    
            
    
    //        combine(handle: { (str1, str2) -> () in
    
    //            print("hello   " + str1 + "  " + str2)
    
    //        })
    
            
    
    //        combine { (str1, str2) in
    
    //            print("hello   " + str1 + "  " + str2)
    
    //        }
    
            
    
            combine {
    
                print("hello   " + $0 + "  " + $1)
    
            }
    
        }

    二、逃逸闭包

     

    当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注 @escaping,用来指明这个闭包是允许“逃逸”出这个函数的。

    一种能使闭包“逃逸”出函数的方法是,将这个闭包保存在一个函数外部定义的变量中。举个例子,很多启动异步操作的函数接受一个闭包参数作为 completion handler。这类函数会在异步操作开始之后立刻返回,但是闭包直到异步操作结束后才会被调用。在这种情况下,闭包需要“逃逸”出函数,因为闭包需要在函数返回之后被调用。例如:

    var completionHandlers: [() -> Void] = []
    
        func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    
            completionHandlers.append(completionHandler)
    
        }
    

    someFunctionWithEscapingClosure(_:) 函数接受一个闭包作为参数,该闭包被添加到一个函数外定义的数组中。如果你不将这个参数标记为 @escaping,就会得到一个编译错误。

     

    使用闭包何时会出现循环强引用 :

    当你把一个闭包分配给类实例属性的时候,并且这个闭包中又捕获了这个实例。捕获可能发生于这个闭包函数体中访问了实例的某个属性,比如 self.someProperty ,或者这个闭包调用了一个实例的方法,例如 self.someMethod() 。这两种情况都导致了闭包捕获了self ,从而产生了循环强引用。

    闭包循环引用的本质是:

    闭包中循环强引用的产生,是因为闭包和类相似(还有一种两个类实例之间的循环强引用),都是引用类型。当你把闭包赋值给了一个属性,你实际上是把一个引用赋值给了这个闭包。两个强引用让彼此一直有效。

    方式一:类似于OC中使用__weak解决block的循环引用,Swift中支持使用weak关键字将类实例声明为弱引用类型(注意,弱引用类型总是可选类型),打破类实例对闭包的强引用,当对象销毁之后会自动置为nil,对nil进行任何操作不会有反应。

    class ThirdViewController: UIViewController {
    
        var callBack: ((String) -> ())?
    
        override func viewDidLoad() {
    
            super.viewDidLoad()
    
            //将self申明为弱引用类型,打破循环引用
    
            weak var weakSelf = self
    
            printString { (text) in
    
                print(text)
    
                //闭包中铺捕获了self
    
                weakSelf?.view.backgroundColor = UIColor.red
    
            }
    
        }
    
        func printString(callBack:@escaping (String) -> ()) {
    
            callBack("这个闭包返回一段文字")
    
            //控制器强引用于着callBack
    
            self.callBack = callBack
    
        }
    
        deinit {
    
            print("ThirdViewController---释放了")
    
        }
    
    }

     

    方式二:作为第一种方式的简化操作,我们可以在闭包的第一个大括号后面紧接着插入这段代码[weak self],后面的代码直接使用self?也能解决循环引用的问题。

    class ThirdViewController: UIViewController {
    
        var callBack: ((String) -> ())?
    
        override func viewDidLoad() {
    
            super.viewDidLoad()
    
            printString {[weak self] (text) in
    
                print(text)
    
                self?.view.backgroundColor = UIColor.red
    
            }
    
        }
    
        func printString(callBack:@escaping (String) -> ()) {
    
            callBack("这个闭包返回一段文字")
    
            //控制器强引用于着callBack
    
            self.callBack = callBack
    
        }
    
        deinit {
    
            print("ThirdViewController---释放了")
    
        }
    
    }
    

    方式三:在闭包和捕获的实例总是互相引用并且总是同时释放时,可以将闭包内的捕获定义为无主引用unowned。

    class ThirdViewController: UIViewController {
    
        var callBack: ((String) -> ())?
    
        override func viewDidLoad() {
    
            super.viewDidLoad()
    
            printString {[unowned self] (text) in
    
                print(text)
    
                self.view.backgroundColor = UIColor.red
    
            }
    
        }
    
        func printString(callBack:@escaping (String) -> ()) {
    
            callBack("这个闭包返回一段文字")
    
            //控制器强引用于着callBack
    
            self.callBack = callBack
    
        }
    
        deinit {
    
            print("ThirdViewController---释放了")
    
        }
    
    }

    注意:unowned是Swift中另外一种解决循环引用的申明无主引用类型的关键字,类似于OC中的__unsafe_unretained;大家都知道__weak和__unsafe_unretained的相同点是可以将该关键字修饰的对象变成弱引用解决可能存在的循环引用。不同点在于前者修饰的对象如果发现被销毁,那么指向该对象的指针会立即指向nil,而__unsafe_unretained修饰的对象如果发现被销毁,指向该对象的指针依然指向原来的内存地址,如果此时继续访问该对象很容易产生坏内存访问/野指针/僵尸对象访问。
    同样的道理Swift中也是一样的。和弱引用类似,无主引用不会牢牢保持住引用的实例。但是不像弱引用,总之,无主引用假定是永远有值的。因此,无主引用总是被定义为非可选类型。你可以在声明属性或者变量时,在前面加上关键字unowned 表示这是一个无主引用。由于无主引用是非可选类型,你不需要在使用它的时候将它展开。无主引用总是可以直接访问。不过 ARC 无法在实例被释放后将无主引用设为 nil ,因为非可选类型的变量不允许被赋值为 nil 。如果此时继续访问已经被释放实例很容易产生坏内存访问/野指针/僵尸对象访问。

    所以Swift建议我们如果被捕获的引用永远不为 nil ,应该用unowned而不是weak,相反,如果你不确定闭包中捕获的引用是不是存在为nil的可能,你应该使用weak。

     

     

     

    展开全文
  • unowned [unowned self] 和 __unsafe__retained作用类似 -&gt; 对象被回收是 内存地址不会自动指向nil 会造成野指针访问 func methodInSwift2() { loadData { [unowned self] (result) in ...

    unowned

    [unowned self] 和 __unsafe__retained作用类似 -> 对象被回收是 内存地址不会自动指向nil 会造成野指针访问

    func methodInSwift2() {
            loadData { [unowned self] (result) in
                print(result,self)
            }
        }
    

    weak

    [weak self] 和 __weak typeof(self) 作用类似 -> 对象被回收是 内存地址会自动指向nil 更加安全 推荐使用这种方式

        func methodInSwift1() {
            loadData { [weak self] (result) in
                let strongSelf = self {
                    print(result,self)
                }
            }
        }
    
    展开全文
  • 解决方法: 1. 使用unowned 声明self(我自己测试不行,可能还需要设置其他的地方,有知道的可以评论留言,谢谢!), 代码: { [unowned self]() -> Void in self.doSomething() } 2. 使用weak 声明self(亲测可行...

    解决方法:

    1. 使用unowned 声明self(我自己测试不行,可能还需要设置其他的地方,有知道的可以评论留言,谢谢!),

    代码:

    <pre name="code" class="plain">{ [unowned self]() -> Void in
            self.doSomething()      
    }
    
    
    2. 使用weak 声明self(亲测可行)

    代码:

    { [weak self]() -> Void in
            self?.doSomething()      
    }






    如果您有其他解决方案,请留言,谢谢!
    展开全文
  • Swift开发文档是这样介绍闭包的:闭包是可以在你的代码被传递和引用的功能性独立模块。Swift 闭包和 C 以及 Objective-C 的 block 很像,还有其他语言的匿名函数也类似。闭包的作用主要是:能够捕获和...
  • Swift 各种闭包各种使用 && 设置参数,函数传值
  • 本文讲的是深入理解 Swift 中闭包的捕捉语义(一), 即使是有ARC的今天,理解内存管理和对象的生命周期仍旧是非常重要的。当使用闭包的时候是一个特例,它在Swift中出现的场景越来越多,比起Objective的代码块的...
  • Swift闭包(Closures)

    2015-10-28 15:20:49
    Swift中闭包与C、OC的blocks和其它编程语言(如Python)的lambdas类似。 闭包可以捕获和存储上下文中定义的的任何常量和变量的引用。这就是所谓的变量和变量的自封闭, 因此命名为”闭包“(“Closures)...
  • 闭包是自包含的函数代码块,可以在代码传递和使用。闭包表达式是一种利用间接语法构建内联闭包的方式。 闭包的表达式(含闭包参数){ (参数列表)->返回值类型 in 语句 }在这里关键字in表示闭包的参数和返回值...
  • swift中闭包是一个很强大的东西,闭包是自包含的函数代码块,可以在代码被传递和使用。跟C 和 Objective-C 的代码块(blocks)很相似 。这个大家必须掌握!必须掌握!必须掌握!重要的事情要说三遍
  • Swift闭包循环引用产生的两个条件1.对象对闭包强引用,即闭包是对象的属性。2.闭包中对对象强引用,闭包对闭包中的成员变量都会强引用一次。Student的实例对printNum闭包强引用,闭包中又对self进行了强引用。 class...
  • 解析Swift中闭包的循环引用
  • Swift闭包详解

    2016-04-13 15:41:28
    Swift函数章节介绍的全局和嵌套函数实际上也是特殊的闭包闭包采取如下三种形式之一: 全局函数是一个有名字但不会捕获任何值的闭包 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包 闭包表达式是
  • 基本操作就是在第二个页面定义一个闭包函数,然后在第一个页面将定义好的函数,通过函数指针传递到第二个页面,然后就阔以了。废话不多说,直接上代码// // ViewController.swift // SwiftClosure // // Created by ...
  • Swift中闭包用法详解

    2016-07-21 23:23:26
     Swift 闭包与 C 和 Objective-C的( blocks) 以及其他一些编程语言的 lambdas 比较相似。 闭包可以 捕获 和存储其所在上下文任意常量和变量的引用。 这就是所谓的闭合并包裹着这些常量和...
  • 5.Swift 闭包

    2018-06-12 20:12:52
    swift 中闭包的范围比较广泛,不只是 oc block 这种的,还包含像上节讲到的全局函数和嵌套函数,全局函数是一种有名字但不会捕获任何只的闭包。嵌套函数是一种有名字可以捕获其封闭函数块的值。 一般...
  • Swift 传值之闭包传值

    2016-01-29 16:37:31
    Swift闭包传值和OC的block传值非常相似 项目的建立和之前的属性传值和代理传值类似  属性传值:http://blog.csdn.net/zhangjitao_boke/article/details/50606185 代理传值:...
  • swift 闭包回调

    2018-08-05 23:03:39
    @noescape在swift3.0已经被废弃,在swift3.0@noescape被用作一个默认值。 @escaping属性写在参数类型的前面而不是参数名称的前面。这是swift3里一个新的点。   这里需要先介绍一下escape的概念。当一个闭包...
  • Swift中闭包,懒加载,单例的写法区别
  • swift闭包传值

    2017-03-16 19:47:39
    在oc我们使用block进行传值,相比其他的方法更加紧凑,在swift中闭包,完全保持这个优点。下面我们来看看闭包传值的三部曲,我们首先假设一种场景,我们从A控制器跳转B控制器,在B控制器,跳转回A控制器的时候,...
1 2 3 4 5 ... 20
收藏数 8,055
精华内容 3,222
关键字:

swift 中的闭包