swift中的开发技巧总结(二)

@autoclosure的使用

定义一个尾随闭包

func logIfTrue(_ predicate: () -> Bool) {
    //不要写 predicate,一定要加上()
    if predicate() {
        print("true")
    } else {
        print("false")
    }
}

调用时显示的样式:

image.png

可以使用这些种写法调用:

        logIfTrue { () -> Bool in
            return 5 > 6
        }
        logIfTrue { () -> Bool in
            6 > 10
        }
        logIfTrue {
            return 7 > 1
        }
        logIfTrue {
            7 > 1
        }

虽然logIfTrue { 7 > 1 }这样写十分的简单明了,但是使用{}还是让人有些困惑.

使用@autoclosure来声明闭包:

//仅仅是作为对比,命名不够规范
func _logIfTrue(_ predicate: @autoclosure () -> Bool) {
    //不要写 predicate,别忘了()
    if predicate() {
        print("true")
    } else {
        print("false")
    }
}

调用的提示:

image.png

使用:

//貌似只能这么写
        _logIfTrue (7 > 1)

注意: @autoclosure只支持() -> T,并不支持带有输入参数的写法.

逃离闭包@escaping 的使用

    func doWork(block: () -> ()) {
        block()
    }

注意:在这种闭包中,block参数中的内容会在dowork返回前调用,也就是block的调用是同步行为.

如果我们开启了异步,让block在dowork返回后被调用,那么就需要@escaping来表明这个闭包会”逃逸”出该方法的:

image.png

    func doWorkAsync(block: @escaping () -> ()) {
        DispatchQueue.main.async {
            block()
        }
    }

注意: 我们知道,闭包是可以捕获变量的.在dowork中没有逃逸行为的闭包,原因是因为闭包的作用域不会超过函数本身,所以我们不必担心在闭包内持有self.而接受@escaping的闭包则不同,由于需要确保闭包内的成员依旧有效,因此当我们在闭包内引用了self及其成员的时候,swift便会强制要求我们写出self.

image.png

class User {
    var name = "lxx"
    func doWork(block: () -> ()) {
        block()
    }
    func doWorkAsync(block: @escaping () -> ()) {
        DispatchQueue.main.async {
            block()
        }
    }
    func method1() {
        doWork {
            print(name)
        }
        name = "dll"
    }
    func method2() {
        doWorkAsync {
            print(self.name)
        }
        name = "lmy"
    }
}

调用:

    override func viewDidLoad() {
        super.viewDidLoad()
        User().method1()///lxx
        User().method2()///lmy
    }

如果我们不希望在闭包中持有self,则可以使用[weak self]来声明表达式:

image.png

    func method3() {
        doWorkAsync {
            [weak self] in
            print(self?.name ?? "nil")
        }
    }

注意此处的调用结果为”nil”

 User().method3()///nil

在协议中的使用:

protocol P {
    func work(block: @escaping () -> ())
}
class User: P {
    // 协议方法也需要使用@escaping
    func work(block:  @escaping () -> ()) {

    }
}

swift 成员变量的声明

image.png
共有两种解决办法:

class User {
    //因为是let,意味着这样初始化后就无法再做修改
    let name: String = ""
}
class User {
    let name: String
    init(name: String) {
        self.name = name
    }
}

        let user = User(name: "liuxingxing")
        print(user.name)

操作符

重载操作符

struct Vector2D {
    var x = 0.0
    var y = 0.0
}
func + (left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let v1 = Vector2D(x: 10, y: 20)
        let v2 = Vector2D(x: 5, y: 8)
        let v3 = v1 + v2
        print(v3)

    }
}

自定义操作符

import UIKit
struct Vector2D {
    var x = 0.0
    var y = 0.0
}

precedencegroup DotProductPrecedence {
    associativity: none
    higherThan: MultiplicationPrecedence
}
infix operator +*: DotProductPrecedence
//+*并不是系统的,所以不能通过重载的方式来实现,必须要声明操作符
func +* (left: Vector2D, right: Vector2D) -> Double {
    return  left.x * right.x +  left.y * right.y
}
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let v1 = Vector2D(x: 10, y: 20)
        let v2 = Vector2D(x: 5, y: 8)
        let v3 = v1 +* v2
        print(v3)//210.0
    }
}

precedencegroup: 定义了一个操作符的优先级别.操作符优先级的定义和类型声明有些相似,一个操作符必须要属于某个特定的优先级.swift库中已经定义了一些常用的运算符优先级组,比如加法优先级(AdditionPrecedence)和乘法优先级(MultiplictionPrecedence)等,如果没有适合自己的优先级组,就需要自己指定结合律方式和优先级顺序了.

associativity:定义了结合律.即如果多个同类的操作符顺序出现的计算顺序.比如常见的加法和减法都是left,就是说多个加法同事出现时按照从左往右的顺序计算(因为加法满足交换律,随意这个顺序无所谓,但是减法的话计算顺序就很重要). 我们定义的点乘不会再和其他的点乘结合使用,所以这里使用none

higherThan: 运算符的优先级.点乘运算是优于乘法的.除了higherThan,也支持lowerThan来指定优先级低于某个其他组.

infix:定义一个中位操作符.即前后都是输入,其他的修饰还包括prefix,postfix.


   转载规则


《swift中的开发技巧总结(二)》 刘星星 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
RxSwift基础总结 RxSwift基础总结
1.创建可观察对象Observable下面都是创建可观察对象的方式: enum MyError: Error { case errorA case errorB }//创建可观察对象 let _ = Observable
2019-03-01
下一篇 
Flex布局的基本使用总结 Flex布局的基本使用总结
Flex布局的基本使用总结flex布局是微信小程序开发推荐使用的布局样式,更易上手和学习。你可以从阮一峰的博客中系统学习到Flex布局,下面是我自己学习上手的记录总结。 1.初始化我们的布局.userContainer { b
2018-12-31
  目录