了解Swift闭包

在上一篇文章中,我们讨论了面向协议的编程及其为我们带来的优势。 今天,我们看一下Swift闭包,并问我们自己如何利用它们的简短语法来使我们的代码更好。

什么是封包?

闭包是可以独立传递的功能块,可以在代码中传递和使用。 Swift中的闭包类似于C和Objective-C中的块,以及其他编程语言中的lambda。

上面的报价直接来自《 Swift语言指南》,尽管看起来似乎什么也没解释,但实际上是对闭包的非常准确的描述。 让我们看看当听到“ closure”一词时,大多数人可能会想到什么,即尾随闭包。

  URLSession.shared.dataTask(with:url){(data,response,error)in 

//处理您从请求中获得的任何很棒的东西

}

这是一种很常见的尾随闭包。 在这种情况下,我们使用Foundation Framework中的函数对所需的某些数据进行异步请求。 然后,我们使用尾随闭包来指定我们希望在数据可用时要对其执行的操作。

对于不太熟悉闭包及其语法的开发人员,似乎我们只是无处不在地以某种方式提取了三个参数,它们神奇地起作用了。 为了了解为什么要指定这些参数名称,并使我们更容易使用尾随闭包来声明自己的函数,我们将看一下.dataTask(with:completionHandler:)函数的虚拟实现。

  func dataTask(带有url:URL,completionHandler :(数据?,URLResponse ?、错误?)->无效){ 

//完成工作以获取我们请求的数据
让数据:数据? = {...}

//获取负载响应
让响应:URLResponse? = {...}

//如果未获取任何数据,则会产生错误
让错误:错误? = {...}


//我们获得了所需的所有信息,
//让我们将其发送给我们的闭包进行最终处理

completeHandler(数据,响应,错误)
}

即使这是在此功能的实际实现中发生的情况的非常粗略的概述,它仍将准确地描述我们感兴趣的行为,即闭包如何在方法工作流中合并和使用。

看一下方法声明,在名为completionHandler的参数上,注意类型声明:

(Data?, URLResponse?, Error?) -> Void

这告诉编译器,我们的.dataTask方法希望传递另一个函数作为参数。 它还希望该函数将三个非常特定的类型作为其自变量。 这些是我们在尾随闭包中命名的参数。

基本上,我们的程序告诉URLSession获取一些数据,然后指定将其删除的位置,以便我们可以继续进行更新。

DispatchQueue关闭

我们钟爱的DispatchQueue类还带有一些将闭包作为参数的函数。 看一下这个.async(execute:)调用:

  DispatchQueue.main.async { 
//执行更新等
}

这有点棘手,因为当您阅读DispatchQueue的文档时,它告诉我们该方法将DispatchWorkItem作为参数。 我们正在尝试传递类型为() -> Void的闭包表达式,为什么这样做有效?

如果深入研究文档,则会发现DispatchWorkItem初始化程序的声明:

 init(qos: DispatchQoS = default, flags: DispatchWorkItemFlags = default, block: @escaping () -> Void) 

让我们分解一下。 在创建DispatchWorkItem时,我们将其传递给DispatchQoS参数,DispatchWorkItemsFlags参数以及不带任何参数且不返回任何内容的函数。 关于它的构造方式,最酷的是前两个参数具有默认值,这意味着如果我们不想更改这些默认值,则可以忽略这些默认值。 这意味着当我们将闭包传递给.async(execute:)方法时,它将被包装在DispatchWorkItem对象中,而其余参数则使用默认值。 真好!

让我们快速看一下分派队列运行我们提交的代码时发生的虚拟实现:

 让nextItem = getNextItemFromQueue() 
 如果!nextItem.isCancelled { 
//这是我们的闭合块所在的位置
//展开并执行。
nextItem.perform()
}

队列在我们的工作项上调用.perform() ,并且不传递任何参数。 这正是上面的声明告诉我们的,这就是为什么在创建DispatchWorkItem时不必在尾随闭包中命名任何参数的原因。 在下一行时,工作项实际上将在实际的代码块上进行相同类型的调用-不带参数,也没有返回值。

本周就这样! 希望通过对闭包的快速了解,可以对如何使用闭包以及如何将其合并到自己的项目中产生新的理解!

如果您有任何疑问,请随时发表评论,然后继续获取有关未来文章的通知。