美文网首页
Swift高阶语法

Swift高阶语法

作者: 鄭经仁 | 来源:发表于2021-07-01 17:29 被阅读0次

    1.数组元素类型转换map

    //swift为函数的参数自动提供简写形式,$0代表第一个参数,$1代表第二个参数
    let array = ["1", "2", "3"]
    let str1 = array.map({ "\($0)"}) //数组每个元素转成String类型
    //字符串数组转NSInteger类型数组
    let array1 = array.map { (obj) -> NSInteger in
        return NSInteger(obj) ?? 0
    }
    //NSInteger类型数组转字符串数组
    let array2 = array1.map { (obj) -> String in
        return String(obj)
    }
    print("array1: \(array1)")
    print("array2: \(array2)")
    //str1 ["1", "2", "3"]
    //array1: [1, 2, 3]
    //array2: ["1", "2", "3"]
    
    举例 ,年月日字符串分割成数组,这时数组是Substring类型数组,需要定义Substring数组,否则无法转换
    var timeArray = [Substring]()
    timeArray = (model.functionTitle?.split(separator: "-"))!
    guard timeArray.count > 0 else {
        return
    }
    //let dataArray = timeArray.map { (obj) -> NSInteger in
     //   return NSInteger(obj) ?? 0
    //}
    //可以省略写法
    let dataArray = timeArray.map {return NSInteger($0) ?? 0}
    
    flatMap, 功能跟map类似; 区别是flatMap会过滤nil元素, 并解包Optional。
    flatMap还可以将多维数组转换为一维数组,对于N维数组, map函数仍然返回N维数组。
    let array = [[1, 2, 3],[1, 2, 3],[1, 2, 3]]
    let arrret = array.flatMap{$0}
    let arrret1 = array.map{$0}
    print(arrret)
    print(arrret1)
    //[1, 2, 3, 1, 2, 3, 1, 2, 3]
    //[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
    
    filter函数, 顾名思义就是过滤出符合条件的元素。
    let array = [1, 2, 3]
    let resultArray = array.filter { return $0 > 1 }
    print(resultArray)
    //[2, 3]
    

    2.匿名函数

    函数可以使用func关键字创建,也可以使用{ }(花括号)来创建,这种方法可以称为匿名函数
    //第一种写法
    func doublerTest(i: Int) -> Int {
        return i * 2
    }
    [1,2,3,4].map(doublerTest)
    
    //第二种写法 (匿名函数)
    let doublerTest1 = {(i: Int) -> Int in
        return i * 2
    }
    [1,2,3,4].map(doublerTest1)
    
    上述这两种出了传参的处理上略有不同,其实是完全等价的。

    3.闭包表达式

    1.正常函数
    //正常函数
    func fn(v1:Int,v2:Int) -> Int {
         v1+v2
    }
    //闭包
    
    //闭包写法
    {
        (参数) -> 返回值类型 in
         函数体代码
    }
    //闭包调用写法
    var fn1 = {
        (v1:Int,v2:Int) -> Int in
        return v1 + v2
    }
    
    //闭包调用简写1
    var fn2 = {
        (v1:Int,v2:Int) in
         v1 + v2
    }
    
    print(fn(v1: 10, v2: 12))
    print(fn1(10,20))
    print(fn2(10,20))
    
    2.函数嵌套
    //正常函数
    func sum(v1:Int,v2:Int,fn:(Int,Int) -> Int ) {
        print(fn(v1, v2))
    }
    //正常函数
    func fn(v1:Int,v2:Int) -> Int {
         v1+v2
    }
    
    //闭包调用简写1
    sum(v1: 10, v2: 20,fn: {
        (v1:Int,v2:Int)  -> Int in
        return v1+v2
    })
    
    //闭包调用简写2
    sum(v1: 10, v2: 20,fn: {
        (v1:Int,v2:Int) in
        return v1+v2
    })
    
    //闭包调用简写3
    sum(v1: 10, v2: 20,fn: {
        (v1,v2) in
        return v1+v2
    })
    
    //闭包调用简写4
    sum(v1: 10, v2: 20,fn: {
        v1,v2 in
        return v1+v2
    })
    
    //闭包调用简写5
    sum(v1: 10, v2: 20,fn: {
        v1,v2 in
        v1+v2
    })
    
    //闭包调用简写6
    sum(v1: 10, v2: 20,fn: {
       $0 + $1
    })
    
    //尾随闭包写法
    //闭包调用简写7
    sum(v1: 10, v2: 20) { v1, v2 in
        v1 + v2
    }
    
    //闭包调用简写8 
    sum(v1: 10, v2: 20) { $0 + $1
    }
    
    
    最完美写法尾随闭包
    //尾随闭包调用简写8
    sum(v1: 10, v2: 20) { $0 + $1
    }
    
    3.尾随闭包
    1.如果很长的闭包表达式作为函数的最后一个实参(必须最后一个实参),使用尾随闭包可以增强函数的可读性,尾随闭包是一个被书写在函数调用括号外面(后面)的闭包表达式,如上闭包调用简写8
    2.如果闭包表达式作为函数的唯一实参,并且使用了尾随闭包的语法,那就不需要在函数后面写圆括号
    //正常函数
    func sum(fn:(Int,Int) -> Int ) {
        print(fn(1, 2))
    }
    
    func fn(v1:Int,v2:Int) -> Int {
         v1+v2
    }
    
    //调用简写1
    sum { v1, v2 in
        v1+v2
    }
    //调用简写2
    sum {$0+$1}
    

    4.闭包(闭包和闭包表达式是两种概念)

    一个函数和它所捕获的变量\常量环境组合起来,称为闭包
    一般指定义在函数内部的函数
    一般它捕获的是外层函数的局部变量\函数
    //定义Fn类型是参数int返回int的方法
    typealias Fn = (Int) -> Int
    
    func getFn() -> Fn{
        //局部变量,
        var num = 0
        func plus(i: Int) -> Int {
            num += i
            return num
        }
        return plus
    }//返回的plus和num形成了闭包
    
    //上面方法等同下面方法
    func getFn1() -> Fn{
        //局部变量
        var num = 0
        return {
            num += $0
            return num
        }
    }//返回的plus和num形成了闭包
    let fn = getFn()//这就是闭包,可以放放局部变量、常量
    
    print(fn(1))
    print(fn(2))
    print(fn(3))
    print(fn(4))
    //返回1 3 6 10
    let fn1 = getFn()//这就是闭包,可以放放局部变量、常量
    print(fn1(1))
    print(fn1(3))
    //返回1 4
    
    如果不初始化方法局部变量放在堆空间,所以不会销毁,如果初始化会销毁对空间
    闭包可以想象成一个类的实例对象,内存在堆空间
    当需要一个方法返回一个方法对象给别人时,就需要用到闭包

    5.Error处理

    1.返回类型后面加? 可选类型
    func divide(num1:Int,num2:Int) -> Int? {
        if num2 == 0 {
            return nil
        }
        return num1/num2
    }
    print(divide(num1: 1, num2: -1))
    
    2.do try-catch
    //1.创建自定义的异常枚举,并遵守 Error 协议:
    enum someError: Error{
        case illegalArg(String)
        case ourtOfBounds(Int,Int)
    }
    //2.主要涉及关键字 throws、throw 的用法,代码形式如下:
    func divide(num1:Int,num2:Int) throws-> Int {
        if num2 == 0 {
            throw someError.illegalArg("0不能作为除数")
        }
        return num1/num2
    }
    3.在 do 中 try 可以抛出错误的方法、并调用继续执行的方法;在 catch 中处理响应的错误,并且 catch 的写法多种多样(可以在多个 catch 中分别 捕获不同错误,也可以在 catch 中 通过 switch case 分别进行捕获),所有捕获的情况一定要写全。
    func test() {
        do {
            print(try divide(num1: 1, num2: 0))
        } catch let someError.illegalArg(msg) {
            print("参数异常",msg)
        } catch let someError.ourtOfBounds(size ,index){
            print("内存溢出","size\(size)","index\(index)")
        } catch {
            print("其他错误")
        }
    }
    
    3.特殊关键字 try!、try?
    try!、try?调用可能抛出Error的函数,这样就不用去处理Error(try?、try!修饰的方法里还是需要做判断处理抛出异常)
    若确定可能抛出异常的某方法本次不抛出异常,则可前置 try! 来调用,可一旦这段代码抛出了一个异常,则会引起运行时错误。
    try? 代表方法可能抛出错,也可能没错,如果发生错误,那么返回nil,如果没有发生错误,系统会把数据包装成一个可选类型的值返回。
    enum someError: Error{
        case illegalArg(String)
        case ourtOfBounds(Int,Int)
    }
    //2.主要涉及关键字 throws、throw 的用法,代码形式如下:
    func divide(num1:Int,num2:Int) throws-> Int {
        if num2 == 0 {
            throw someError.illegalArg("0不能作为除数")
        }
        return num1/num2
    }
    func test() {
        var result1 = try? divide(num1: 10, num2: 10)
        var result2 = try? divide(num1: 10, num2: 0)
        var result3 = try! divide(num1: 10, num2: 10)
    }
    
    下面两个定义是等价的
    var a = try? divide(num1: 10, num2: 0)
    var b: Int?
    do {
        try b = divide(num1: 10, num2: 0)
    } catch {
        b = nil
    }
    
    4. rethrows表名:函数本身不回抛出错误,但调用闭包参数抛出错误,那么它会将参数向上抛
    5.defer语句:用来定义以任何方式(抛出错误、return等)离开代码块之前必须执行的代码,defer语句讲延迟至当前作用域结束之前执行
    enum someError: Error{
        case illegalArg(String)
        case ourtOfBounds(Int,Int)
    }
    func divide(num1:Int,num2:Int) throws-> Int {
        if num2 == 0 {
            throw someError.illegalArg("0不能作为除数")
        }
        print(num1/num2)
        return num1/num2
    }
    
    func result()  {
        defer {
            print("必须执行")
        }
        try? divide(num1: 10, num2: 0)
    }
    

    6.泛型

    泛型是可以将类型参数化,提高代码复用率,减少代码量。可以用在类、结构体、函数、枚举
    //元素交换方法
    func swapValues<T>(_ a: inout T,_ b:inout T )  {
        (a,b) = (b,a)
    }
    var a = 10
    var b = 20
    swapValues(&a, &b)
    
    var c = 10.05
    var d = 20.05
    swapValues(&c, &d)
    

    7.关联类型

    关联类型用在协议中,协议可以又多个关联类型
    protocol Stackable {
        associatedtype Element //关联类型
        associatedtype Element1 //关联类型
        associatedtype Element2 //关联类型
        mutating func push(_ element: Element)
        mutating func pop() -> Element
        func top() -> Element
        func size() -> Int
    }
    
    
    class strungStack: Stackable {
    
        typealias Element1 = Int
    
        typealias Element2 = Double
    
        typealias Element = String///给关联类型定义真实类型
    
        func push(_ element: Element) {
    
        }
    
        func pop() -> Element {
            return "111"
        }
    
        func top() -> Element {
            return "111"
        }
    
        func size() -> Int {
            return 111
        }
    
    }
    

    相关文章

      网友评论

          本文标题:Swift高阶语法

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