OMG, 闭包的参数标签可以省略,就连()也可以省略
方法名后直接跟的大括号
数组是二等类型吗?请看下面AI的回答
在Swift中,数组是一种二等类型(second-class type)。
这是因为Swift的数组类型在某些操作上受到了限制,无法直接进行一些高级操作,
例如在某些情况下无法作为字典的键或者以某些方式进行泛型编程。
总的来说,虽然Swift提供了许多高级特性,但是数组在某些情况下不能被当作完全的类型。
这也是为什么它被称为二等类型的原因。
呃,枚举是一等类型。。。
因为。。。
它们采用了很多在传统上只被类(class)所支持的特性,
例如计算属性,例如实例方法,例如构造函数,例如遵循协议。。。
枚举简单的说是一种数据类型,只不过是这种数据类型只包含自定义的特定数据,它是一组有共同特性的数据的集合。
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
//这是一个平凡无奇的字符串数组
let customerProvider = {customersInLine.remove(at: 0)}
print("String is \(customerProvider()), and count \(customersInLine.count)")
func serve(customer customerProvider: () -> String){
print("Remove the \(customerProvider()) now is \(customersInLine.count)")
}
serve(customer: {customersInLine.remove(at: 0)})
func registerUser(username: String, completion: @escaping (Bool) -> Void) {
let validateUsername = {
return username.count > 3 && !username.isEmpty
}
let sendVerificationEmail = {
print("Verification email sent to \(username)!")
return true
}
let saveUserInfo = {
print("User \(username) info saved!")
return true
}
if validateUsername() {
if sendVerificationEmail() {
if saveUserInfo() {
completion(true)
} else {
completion(false)
}
} else {
completion(false)
}
} else {
completion(false)
}
}
registerUser(username: "testUser") { success in
if success {
print("Registration Successful!")
} else {
print("Registration Failed!")
}
}
在这个例子中,通过将每个步骤封装为一个闭包,可以让代码的逻辑更加清晰,容易理解。
而且一旦需要修改某个步骤(例如更改验证逻辑或发送邮件的方式),你只需在相应闭包中进行更改,
而不需要重构整个函数。
func path(in rect: CGRect) -> Path {
var path = Path()
let radius = min(rect.width / 2, rect.height / 2)
let center = CGPoint(x: rect.width / 2, y: rect.height / 2)
var nextPoint = CGPoint.zero
let ithPoint: (Int) -> CGPoint = { i in
let point = center + CGPoint(x: radius * sin(CGFloat(i) * CGFloat.pi * CGFloat(2) / CGFloat(pointsNum)),
y: radius * cos(CGFloat(i) * CGFloat.pi * CGFloat(2) / CGFloat(pointsNum)))
var direction = CGVector(point - center)
direction = direction / direction.len()
return point + direction * CGFloat(morphing[i >= pointsNum ? 0 : i])
}
for i in (0...pointsNum){
nextPoint = ithPoint(i)
}
……
path.closeSubpath()
return path
}
在这段伪代码中,我问百度,在这里ithPoint为什么要使用闭包?百度答:
封装和复用:
将这段逻辑放入闭包中,允许您轻松重用该逻辑,只需简单地调用闭包。
例如,您可以在绘制形状时多次调用 ithPoint(i) 来得到不同的点。
简化代码:
通过将相关的计算逻辑聚合到一个闭包中,您可以保持代码的结构清晰,便于理解和维护。
上下文捕获:
在这个上下文中,闭包可以方便地访问外部变量如 center、radius、pointsNum 和 morphing,让代码更加简洁。
如果把这个逻辑拆分到多个函数中,就需要通过参数显式地传递这些值,反而可能导致更复杂的调用结构。
评:闭包是一种可以捕获和存储其上下文环境的函数;函数的作用是:把A转化为B;
以前从未真正理解过“上下文捕获”,这里懂了,哪怕你把它改成函数,是需要写很多参数的。
实践了一下,确实可以改写成函数,比如此例子为嵌套函数,但是有两个地方很烦,一个是函数申明时多个参数名,
另一个是函数调用时多个参数名。
发现计算属性和闭包在写法上很像:
var radius: CGFloat = outerSize / 2
当 outerSize 在对象生命周期中比较稳定,或你只需在初始化时计算一次,并且在之后的代码中 radius 不再更改时,
可以选择存储属性。
var radius: CGFloat { outerSize / 2 }
当你希望 radius 始终反映 outerSize 的最新状态,且 outerSize 可能变化频繁时,
使用计算属性是一种更好的选择。
var radius = { outerSize / 2 }
可以控制何时执行计算,适用于更复杂的需求。