你的问题是乱码。您的示例代码无效,并且未显示正在使用的完成处理程序。
我怀疑您误解了异步请求和完成处理程序的工作原理。这是顺序。
- 调用函数并提供完成处理程序
- 函数立即返回,并在未来某个时刻运行请求
- 完成处理程序后的下一行在请求开始处理之前运行。您的应用程序继续运行。由于请求尚未完成,因此无可用结果。
- 异步请求终于完成。原始方法调用完成处理程序。现在,结果在完成处理程序的代码中可用。完成处理程序代码执行处理结果所需的任何操作。
下面是一个带有完成处理程序的异步进程如何工作的实际示例:(您可以在 Github 上找到一个演示此代码的工作 Xcode 项目:这个链接 https://github.com/DuncanMC/SwiftCompletionHandlers.git)
首先是一个 AsyncManager 类,它模拟从互联网下载图像:
class AsyncManager
{
static let sharedAsyncManager = AsyncManager()
func asyncFetchImage(#imageName: String, completion: (image: UIImage?, status: String) -> ())
{
println("Entering \(__FUNCTION__)")
//Simulate a network operation by waiting 3 seconds before loading an image
let nSecDispatchTime = dispatch_time(DISPATCH_TIME_NOW,
Int64(3.0 * Double(NSEC_PER_SEC)))
let queue = dispatch_get_main_queue()
dispatch_after(nSecDispatchTime, queue)
{
() -> Void in
let result = UIImage(named: imageName)
println("Loading image in background")
let status = result != nil ? "image loaded" : "Error loading image"
println("About to call completion handler")
completion(image: result, status: status)
}
println("Leaving \(__FUNCTION__)")
}
}
它是一个单例。它有一个静态的letsharedAsyncManager,您可以使用它来获取AsyncManager的单个实例。
AsyncManager 提供了一个方法 asyncFetchImage,它采用图像名称和完成块。该函数不返回任何结果,因为它在图像加载发生之前立即返回。
该代码并没有真正从互联网下载图像。相反,它只是使用 GCD 调用dispatch_after 在加载图像并调用完成块之前等待 3 秒。
现在我创建一个 ViewController 类并给它一个“加载图像”按钮。我创建一个IBOutlet
theImageView
to a UIImageView
这将显示我要加载的图像。
我为“加载图像”按钮编写了一个 IBAction 方法。 IBAction 如下所示:
@IBAction func loadImage(sender: UIButton)
{
let theAsyncManager = AsyncManager.sharedAsyncManager
println("about to call asyncFetchImage")
theAsyncManager.asyncFetchImage(imageName: "wareto_blue_150x115")
{
(image, status) -> () in
println("Beginning completion block")
self.theImageView.image = image
println("In completion block, status = \(status)")
}
println("After call to asyncFetchImage")
}
}
现在,有趣的部分。以下是事件的顺序:
我按下加载图像按钮。 IBAction 方法运行。
它获取对异步下载管理器单例的引用。
它显示一条消息,然后调用AsyncManager.asyncFetchImage。 AsyncManager.asyncFetchImage 方法在进入时显示一条消息,在 3 秒后将调用排队以加载图像,显示一条“离开”消息,然后返回,在图像加载之前。没有任何内容可返回,因为图像加载代码尚未运行。
视图控制器的 loadImage 方法显示“调用 asyncFetchImage 后”消息并返回。
几秒钟后,asyncFetchImage 内部的代码实际运行。它显示一条消息,加载图像,然后调用完成处理程序。
以下是运行上面的代码时返回的一组消息:
about to call asyncFetchImage
Entering asyncFetchImage(imageName:completion:)
Leaving asyncFetchImage(imageName:completion:)
After call to asyncFetchImage
Loading image in background
About to call completion handler
Beginning completion block
In completion block, status = image loaded
请注意 loadImage IBAction 的最后一行:
println("After call to asyncFetchImage")
在显示有关加载图像的消息之前显示一条消息。在完成任何工作之前,对 asyncFetchImage 的代码调用立即返回。接下来运行调用 asyncFetchImage 后的代码,但图像仍未加载。此时无法返回结果,因为图像加载尚未开始。