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

时间:2016-02-01 23:02:01

标签: ios swift asynchronous ios9

我是swift并使用异步代码的新手。

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

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

因为从API获取信息的方法是异步的,所以我无法从中返回值。而是通过回调:

@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

}

这个工作因为让线程休眠会留下时间让数组被填满。但是,使主线程处于睡眠状态是一个非常糟糕的主意,并且无法保证此时将返回数据。

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

尝试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,这不是很好,并产生以下警告:

  

此应用程序正在从后台线程修改autolayout引擎,这可能导致引擎损坏和奇怪的崩溃。这将在将来的版本中引发异常。

那么,有没有办法在getEventsFromAPI调用完成后更新主线程的UI(即更改标签文本)(这样数组实例变量现在不是nil)?

2 个答案:

答案 0 :(得分:4)

你快到了。最后一招是从主线程调用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
        }           
    })
}

答案 1 :(得分:0)

在Swift 4中,这可以更简单地完成:

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
    }
})