swift - 函数顺序 - 哪个代码在什么时候运行?

swift - order of functions - which code runs when?

我的代码有问题,我认为这可能与调用代码的顺序有关。

import WatchKit
import Foundation


class InterfaceController: WKInterfaceController {

private var tasks = [Task]()

override func willActivate() {
    let taskUrl = "http://myjsonurl.com"
    downloadJsonTask(url: taskUrl)
    print(tasks.count) // EMPTY
    super.willActivate()
}

func downloadJsonTask(url: String) {
    var request = URLRequest(url: URL(string: url)!)
    request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
    URLSession.shared.dataTask(with: request) { data, urlResponse, error in

        guard let data = data, error == nil, urlResponse != nil else {
            print("something is wrong")
            return
        }

        do
        {
            let decoder = JSONDecoder()
            let downloadedTasks = try decoder.decode(Tasks.self, from: data)
            self.tasks = downloadedTasks.tasks
            print(downloadedTasks.tasks.count) //4

        } catch {
            print("somehting went wrong after downloading")
        }

    }.resume()
}
}

我正在定义 private var tasks 并用 downloadJsonTask 函数填充它,但是在函数 运行 之后 print(tasks.count) 给出 0。 当我调用 print(downloadedTasks.tasks.count) 时,它给出 4.

我认为按时间顺序打印时任务变量为空,稍后填充。

当您尝试在 willActivate() 中打印任务数时,函数 downloadJsonTask(url: String) 尚未完成,因此您的数组为空,因为任务尚未设置.

您应该像这样向 downloadJsonTask 添加完成处理程序:

(不要忘记将完成作为函数参数传递)

func downloadJsonTask(url: String, completion: @escaping () -> Void) {
    var request = URLRequest(url: URL(string: url)!)
    request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
    URLSession.shared.dataTask(with: request) { data, urlResponse, error in

        guard let data = data, error == nil, urlResponse != nil else {
            print("something is wrong")
            completion()
            return
        }

        do {
            let decoder = JSONDecoder()
            let downloadedTasks = try decoder.decode(Tasks.self, from: data)
            self.tasks = downloadedTasks.tasks
            print(downloadedTasks.tasks.count) //4
        } catch {
            print("something went wrong after downloading")
        }
        completion() // This is moment when code which you write inside closure get executed

    }.resume()
}

在你的 willActivate() 中使用这样的函数:

downloadJsonTask(url: taskUrl) { 
    print(tasks.count)
}

这意味着当您获取数据时,curly 大括号内的代码将被执行。

您的假设是正确的,即 tasks 在首次打印时尚未被赋值。

问题是网络请求是异步执行的。这意味着 iOS 不会等到 downloadJsonTask(url:) 完成,而是立即继续执行代码(即它在网络请求 started[=26= 后立即调用 print(tasks.count) ], 无需等待它产生任何结果)。

URLSession.shared.dataTask(with:) 后括号内的代码称为 完成处理程序 。一旦网络请求完成(因此得名),就会执行此代码。 tasks 变量只有在请求完成时才会被赋值。您可以通过在 self.tasks = downloadedTasks.tasks:

之后添加 print(self.tasks.count) 来确保它有效
self.tasks = downloadedTasks.tasks
print(self.tasks)
print(downloadedTasks.tasks.count)