zoukankan      html  css  js  c++  java
  • Swift 5.1 新语法

    • Swift 5.1 新语法 单表达式隐式返回值

    在 Swift 5.0 之前的语法中,如果一个闭包表达式只有一个表达式,那么可以省略 return 关键字。 现在 Swift 5.1 以后的版本中计算属性和函数语句同样适用。

    // before swift 5.0 
    
    struct Rectangle {
        var width = 0.0, height = 0.0
        var area1: Double {
            return width * height
        }
        
        func area2() -> Double {
            return width * height 
        }
    }
    
    // after switft 5.1
    struct Rectangle {
        var width = 0.0, height = 0.0
        var area1: Double { width * height }
        
        func area2() -> Double { width * height }
    }

    根据结构体默认成员合成默认初始化器

    在 Swift 5.0 之前结构体声明,编译器会默认生成一个逐一成员初始化器,同时如果都有默认值,还会生成一个无参的初始化器。 但如果此时结构体成员属性过多,且较多都有默认值,则只能使用逐一成员初始化器,会使每处调用的地方写法过于冗余,在传统 OOP 语言中可以使用 Builder 模式解决, 但在 Swift 5.1 之后编译器会按需合成初始化器,避免初始化写法的冗余。

    struct Dog {
        var name = "Generic dog name"
        var age = 0
    }
    let boltNewborn = Dog()
    let daisyNewborn = Dog(name: "Daisy", age: 0)
    // before swift 5.0 
    let benjiNewborn = Dog(name: "Benji")
    // after switft 5.1 
    let benjiNewborn = Dog(name: "Benji")

    字符串插入运算符新设计

    这个特性主要扩大了字符串插入运算符的使用范围,以前我们只能用在 String 的初始化中,但是不能在参数处理中使用字符串插入运算符。 在以前的语法中只能分开书写,虽然没什么大问题,但总归要多一行代码,现在可以只能使用了, 尤其是对于 SwiftUI,Text 控件就使用到了这种新语法,可以使我们在单行表达式中即可初始化

    // before swift 5.0 
    let quantity = 10
    label.text = NSLocalizedString(
        "You have (quantity) apples,
        comment: "Number of apples"
    )
    
    label.text = String(format: formatString, quantity)
    
    // after switft 5.1 
    let quantity = 10
    return Text(.
    "You have (quantity) apples"
    ).
    
    // 实际上编译器会翻译为如下几句
    var builder = LocalizedStringKey.StringInterpolation(
        literalCapacity: 16, interpolationCount: 1
    )
    builder.appendLiteral("You have ")
    builder.appendInterpolation(quantity)
    builder.appendLiteral(" apples")
    LocalizedStringKey(stringInterpolation: builder)

    属性包装器

    当我们在一个类型中声明计算属性时,大部分属性的访问和获取都是有相同的用处,这些代码是可抽取的,如我们标记一些用户偏好设置,在计算属性的设置和获取中直接代理到 UserDefault的实现中,我们可以通过声明 @propertyWarpper 来修饰,可以减少大量重复代码。 在 SwiftUI 中, @State @EnviromemntObject @bindingObject @Binding 都是通过属性包装器代理到 SwiftUI 框架中使其自动响应业务状态的变化。

    // before swift 5.0 
    struct User {
        static var usesTouchID: Bool {
            get {
                return UserDefaults.standard.bool(forKey: "USES_TOUCH_ID")
            }
            set {
                UserDefaults.standard.set(newValue, forKey: "USES_TOUCH_ID")
            }
        }
        static var isLoggedIn: Bool {
            get {
                return UserDefaults.standard.bool(forKey: "LOGGED_IN")
            }
            set {
                UserDefaults.standard.set(newValue, forKey: "LOGGED_IN")
            }
        }
    }
    
    // after switft 5.1 
    @propertyWrapper
    struct UserDefault<T> {
        let key: String
        let defaultValue: T
        init(_ key: String, defaultValue: T) {
            print("UserDefault init")
            self.key = key
            self.defaultValue = defaultValue
            UserDefaults.standard.register(defaults: [key: defaultValue])
        }
        var value: T {
            get {
                print("getter")
                return UserDefaults.standard.object(forKey: key) as? T ??  defaultValue
            }
            set {
                print("setter")
                UserDefaults.standard.set(newValue, forKey: key)
            }
        }
    }
    struct User2 {
        @UserDefault("USES_TOUCH_ID", defaultValue: false)
        static var usesTouchID: Bool
        @UserDefault("LOGGED_IN", defaultValue: false)
        var isLoggedIn: Bool
    }
    
    print("hello world")
    let user = User2()
    User2.usesTouchID = true
    let delegate = User2.$usesTouchID
    print("(delegate)")
    let detelate2 = user.$isLoggedIn
    

    实际上属性包装器是在编译时期翻译为一下的代码, 并且编译器禁止使用 $ 开头的标识符

    struct User2 {
        static var $usesTouchID = UserDefault<Bool>("USES_TOUCH_ID", defaultValue: false)
        static var usesTouchID: Bool {
            set {
                $usesTouchID.value = newValue
            }
            get {
                $usesTouchID.value 
            }
        }
        @UserDefault("LOGGED_IN", defaultValue: false)
        var isLoggedIn: Bool
    }
    

    使用属性包装器的好处除了可以减少重复代码,Swift Runtime 还保证了一下几点

    对于实例的属性包装器是即时加载的 对于类属性的属性保证器是懒加载的 属性包装器是线程安全的 通过 $ 运算符可以获取到原始的属性包装器实例,这大量使用在 SwiftUI 的数据依赖中

  • 相关阅读:
    我藏在你的心里,你却不愿意寻找# BUG躲猫猫
    阴间需求之跨端登录
    神奇的props
    map与filter:你先我先?
    阴间BUG之动态路由刷新几率回首页
    阴间BUG之动态路由添加失败
    我在eltable就变了个模样,请你不要再想我,想起我
    SCP打包部署方法
    indexOf 与 includes
    YACC和BISON学习心得
  • 原文地址:https://www.cnblogs.com/liuxiaokun/p/12680154.html
Copyright © 2011-2022 走看看