Swift - 使用来自异步方法的数据更新视图

Swift - Updating the view with data from an async method

我是 swift 的新手,正在使用异步代码。

我有一个方法可以从 API 中获取数据,将数据放入对象并将这些对象放入数组中。然后我想用数组中那些对象的数据更新 UI 。

为了说明 UI 正在更新,我将更改标签的值。

因为从 API 获取信息的方法是异步的,所以我无法 return 从中获取值。相反,我传递了一个回调:

@IBOutlet var labelTest: UILabel!
private var eventsArray : Array<Event> = Array<Event>()

override func viewDidLoad() {

    APIAccessUtil.getEventsFromAPI({(eventsList: Array<Event>) -> Void in
        self.eventsArray = eventsList
    })

    sleep(5) //this is of course not good, but I'll leave it here to illustrate what's going on. 

    self.labelTest.text = eventsArray[0].description

}

有效 因为让线程休眠会留出时间来填充数组。然而,让主线程休眠是一个非常糟糕的主意,并且不能保证数据会在这段时间内 returned。

如果 sleep(...) 被删除,那么 UI 标签会在 getEventsFromAPI 调用完成之前尝试更新,从而产生运行时错误(因为数组仍然是无)。

尝试 2:

@IBOutlet var labelTest: UILabel!
private var eventsArray : Array<Event> = Array<Event>()

override func viewDidLoad() {

    APIAccessUtil.getEventsFromAPI({(eventsList: Array<Event>) -> Void in
        self.eventsArray = eventsList
        self.labelTest.text = eventsArray[0].description
    }) 
}

在尝试 #2 中,我正在从后台线程更新 UI,这并不好并会产生以下警告:

This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes. This will cause an exception in a future release.

那么,在 getEventsFromAPI 调用完成后,有什么方法可以从主线程更新 UI (即更改标签文本)(这样数组实例变量现在就不是无)?

你快到了。最后的技巧是从主线程调用 UI 更新:

override func viewDidLoad() {

    APIAccessUtil.getEventsFromAPI({(eventsList: Array<Event>) -> Void in
        self.eventsArray = eventsList

        // Update the UI on the main thread
        DispatchQueue.main.async {          
            self.labelTest.text = eventsArray[0].description
        }           
    })
}

在Swift4中,这个可以做得更简单一点:

APIAccessUtil.getEventsFromAPI({(eventsList: Array<Event>) -> Void in
    self.eventsArray = eventsList

    // Update the UI on the main thread
    DispatchQueue.main.async() {
        self.labelTest.text = eventsArray[0].description
    }
})