@autoclosure的使用
定义一个尾随闭包
func logIfTrue(_ predicate: () -> Bool) {
//不要写 predicate,一定要加上()
if predicate() {
print("true")
} else {
print("false")
}
}
调用时显示的样式:
可以使用这些种写法调用:
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")
}
}
调用的提示:
使用:
//貌似只能这么写
_logIfTrue (7 > 1)
注意: @autoclosure只支持
() -> T
,并不支持带有输入参数的写法.
逃离闭包@escaping
的使用
func doWork(block: () -> ()) {
block()
}
注意:在这种闭包中,block参数中的内容会在dowork返回前调用,也就是block的调用是同步行为.
如果我们开启了异步,让block在dowork返回后被调用,那么就需要@escaping
来表明这个闭包会”逃逸”出该方法的:
func doWorkAsync(block: @escaping () -> ()) {
DispatchQueue.main.async {
block()
}
}
注意: 我们知道,闭包是可以捕获变量的.在dowork中没有逃逸行为的闭包,原因是因为闭包的作用域不会超过函数本身,所以我们不必担心在闭包内持有self.而接受
@escaping
的闭包则不同,由于需要确保闭包内的成员依旧有效,因此当我们在闭包内引用了self及其成员的时候,swift便会强制要求我们写出self.
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]
来声明表达式:
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 成员变量的声明
共有两种解决办法:
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.