美文网首页Swift
Swift4 基础部分:Closures

Swift4 基础部分:Closures

作者: Arnold134777 | 来源:发表于2017-07-23 21:15 被阅读1204次

    本文是学习《The Swift Programming Language》整理的相关随笔,基本的语法不作介绍,主要介绍Swift中的一些特性或者与OC差异点。

    系列文章:

    Closures

    闭包表达式语法(Closure Expression Syntax)

    Closure expression syntax has the following general form:
    
     { (parameters) -> return type in
        statements
    }
    

    例子:数组排序的例子

    var names:[String] = ["B","A","C"];
    names = names.sorted(by: {
        (num1:String,num2:String) -> Bool in
        return num1 < num2;
    });
    print(names);
    

    执行结果:

    ["A", "B", "C"]
    

    上下文检测类型(Inferring Type From Context)

    Because the sorting closure is passed as an argument to a 
    method, Swift can infer the types of its parameters and 
    the type of the value it returns. The sorted(by:) method 
    is being called on an array of strings, so its argument 
    must be a function of type (String, String) -> Bool. This 
    means that the (String, String) and Bool types do not need 
    to be written as part of the closure expression’s 
    definition.
    
    • 排序的闭包因为Swift中的类型检测机制,所以可以省掉写入String,-> Bool

    针对上述的例子做简化:

    var names:[String] = ["B","A","C"];
    names = names.sorted(by: {
        (name1,name2) in
        return name1 < name2;
    });
    print(names);
    

    单表达式闭包的隐式返回(Implicit Returns from Single-Expression Closures)

    Single-expression closures can implicitly return the 
    result of their single expression by omitting the return 
    keyword from their declaration
    
    • 单表达式的闭包可以省略掉return关键字

    继续简化上述例子:

    var names:[String] = ["B","A","C"];
    names = names.sorted(by: {
        (name1,name2) in name1 < name2;
    });
    print(names);
    

    参数名称缩写(Shorthand Argument Names)

    Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.
    
    • 结合闭包中类型的检测,闭包中的参数名可以使用$0, $1, $2代替

    继续简化上述例子:

    var names:[String] = ["B","A","C"];
    names = names.sorted(by: {
        $0 < $1;
    });
    print(names);
    

    操作方法(Operator Methods)

    There’s actually an even shorter way to write the closure 
    expression above. Swift’s String type defines its string-
    specific implementation of the greater-than operator (>) 
    as a method that has two parameters of type String, and 
    returns a value of type Bool.
    
    • 继续简化可以直接用>,<表示比较结果

    继续简化例子:

    var names:[String] = ["B","A","C"];
    names = names.sorted(by:<);
    print(names);
    

    尾随闭包(Trailing Closures)

    If you need to pass a closure expression to a function as 
    the function’s final argument and the closure expression 
    is long, it can be useful to write it as a trailing 
    closure instead. A trailing closure is written after the 
    function call’s parentheses, even though it is still an 
    argument to the function. When you use the trailing 
    closure syntax, you don’t write the argument label for the 
    closure as part of the function call.
    
    • 当闭包是函数中的最后一个参数时,函数调用可以省略掉参数标签的写法,简化函数

    闭包是引用类型数据(Closures Are Reference Types)

    In the example above, incrementBySeven and incrementByTen 
    are constants, but the closures these constants refer to 
    are still able to increment the runningTotal variables 
    that they have captured. This is because functions and 
    closures are reference types.
    
    • Swift中的闭包是引用类型的数据

    例子:

    var num = 0;
    func increment(completion:() -> Void){
        completion();
        print("num:\(num)");
    }
    increment {
        num += 10;
    }
    let referIncrement = increment;
    referIncrement{
        num += 20;
    }
    

    执行结果:

    num:10
    num:30
    

    逃逸闭包(Escaping Closures)

    A closure is said to escape a function when the closure is 
    passed as an argument to the function, but is called after 
    the function returns. When you declare a function that 
    takes a closure as one of its parameters, you can write 
    @escaping before the parameter’s type to indicate that the 
    closure is allowed to escape.
    
    • Swift中如果需要逃逸闭包需要利用关键字@escaping修饰

    例子:

    var completionHandlers: [() -> Void] = []
    func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
        completionHandlers.append(completionHandler)
    }
    
    func someFunctionWithNonescapingClosure(closure: () -> Void) {
        closure()
    }
    
    class SomeClass {
        var x = 10
        func doSomething() {
            
            someFunctionWithEscapingClosure(completionHandler: {
                self.x = 100;
            });
            
            someFunctionWithNonescapingClosure(closure: {
                x = 200;
            });
            
            // 以下的调用方式一样可行,同时说明了尾随闭包的使用
            //someFunctionWithEscapingClosure { self.x = 100 }
            //someFunctionWithNonescapingClosure { x = 200 }
        }
    }
    let instance = SomeClass()
    instance.doSomething()
    print(instance.x)
    completionHandlers.first?()
    print(instance.x)
    

    执行结果:

    200
    100
    

    自动闭包(Autoclosures)

    An autoclosure is a closure that is automatically created 
    to wrap an expression that’s being passed as an argument 
    to a function. It doesn’t take any arguments, and when 
    it’s called, it returns the value of the expression that’s 
    wrapped inside of it.
    
    • Swift中的自动闭包能动态的封装一个表达式为一个函数的参数,自动闭包不能带任何的参数

    例子:

    
    var num = 1;
    func filter(contions:() -> Bool){
        if contions(){
            num += 3;
            print("num:\(num)");
        }else{
            num += 1;
            print("num:\(num)");
            filter(contions: {num % 3 == 0})
        }
    }
    filter(contions: { num % 3 == 0 })
    

    执行结果:

    num:2
    num:3
    num:6
    

    下面开始利用@autoclosure简化:

    var num = 1;
    func filter(_ contions: @autoclosure () -> Bool){
        if contions(){
            num += 3;
            print("num:\(num)");
        }else{
            num += 1;
            print("num:\(num)");
            filter(num % 3 == 0)
        }
    }
    filter(num % 3 == 0)
    
    Overusing autoclosures can make your code hard to 
    understand. The context and function name should make it 
    clear that evaluation is being deferred.
    
    • autoclosure的过度使用并不好,会让代码逻辑看起来更难理解,必须了解上下文中函数的定义才可结合使用

    相关文章

      网友评论

        本文标题:Swift4 基础部分:Closures

        本文链接:https://www.haomeiwen.com/subject/pqzmkxtx.html