更新数据与更新UI困境

时间:2015-02-23 10:02:35

标签: ios asynchronous nsurlsessiondatatask

我最近使用Swift开发了一个iOS应用程序,它根据响应数据处理大量后台HTTP任务,不仅更新UI,还更新当前会话的静态数据(大量数组,变量等)。在iOS开发中我可能被认为是新手,有一些我感到困惑的地方:

通过GCD API处理从后台任务更新UI。我总是使用以下方法处理这些更新:

dispatch_async(dispatch_get_main_queue, {
    // Update UI
})

让我给出一个场景并澄清我的观点:

我有一个带UITableView子视图的视图控制器。此表视图将显示某些内容列表(例如用户名)。我准备并恢复了NSURLSessionDataTask:

let request = NSMutableURLRequest(URL: someURL)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
    data, response, error in

    // Handle error case
    // Parse data, and receive a user list
    // AppData.userList = parsed list
    // Update table view
}

我的一些测试人员遇到了一些与调度调用和运行循环相关的崩溃,其中我无法找到原因。我认为这与我的调度电话有关。现在我正在重新考虑我的设计,这是我的问题:

  • 在http任务的完成处理程序中更新主队列上的dispatch_async调用内部和外部的静态数据(数组,字典等)有什么区别(无论如何,在更新后,UI将在调度调用内更新)在我的数据上)?在读取,插入或从阵列中删除时,如何确保后台线程的线程安全?
  • 在闭包内(对于任务完成处理程序)进行dispatch_async调用是否会导致任何问题?

任何明确的评论或指导都会非常有帮助!非常感谢现在

2 个答案:

答案 0 :(得分:2)

即使我对答案没有清晰的认识,我也会尝试给你一个aswer。
您必须从主线程更新UI,因为UIKit对象(如果要在屏幕外位图上下文中绘制,则存在一些异常)不是线程安全的。
以下是苹果对此的评价:

  

注意:在大多数情况下,UIKit类只能用于   应用程序的主要线程。对于课程尤其如此   源自UIResponder或涉及操纵你的   应用程序的用户界面。

所有渲染例程都应该在主线程上运行,很可能是由于GPU加速和事件管理 相比之下,Foundation对象(除了一些可变的线程是安全的),因此可以在不同的线程上管理/操作和使用它们。
线程安全意味着您可以轻松地在线程之间共享对象 如果你在后台线程上使用Foundation对象就没有任何问题,如果你在该线程内部使用mutable,一切都应该工作,当你想要将对象添加到数组(例如)时,会出现可变对象的问题更多线程。
如果你提供自己的课程,你应该自己提供线程安全。

答案 1 :(得分:0)

首先要做的事情:

let request = NSMutableURLRequest(URL: someURL)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { [weak self]
(data, response, error) in
    if let weakself = self {
        // ...
        dispatch_async(dispatch_get_main_queue()) {
            // update UI
        }
    }
}

每当您进行异步调用时,您需要确保没有self引用以防止任何可能的循环引用(内存泄漏)。

  

在http任务的完成处理程序中更新主队列上的dispatch_async调用内部和外部的静态数据(数组,字典等)有什么区别(无论如何,在更新后,UI将在调度调用内更新)在我的数据上)?在读取,插入或从数组中删除时,如何确保后台线程的线程安全?

更新dispatch_async内外的数据没有区别。您只需要确保在迭代它们时不要改变数组或字典。您可以通过锁定数据结构或创建临时浅拷贝来完成此操作。

例如,如果您正在读取可能被另一个线程更改的数组:

var integers = Array<Int>()

// The following creates an IMMUTABLE shallow copy of mutable array
let ints = integers

for value in ints {
   // use value
}

// OR use locking
objc_sync_enter(integers)
for value in integers {
   // use value
}
objc_sync_exit(integers)

// in another thread - lock before mutating
objc_sync_enter(integers)
integers.append(someIntValue)
objc_sync_exit(integers)

当然,您可以使用其他锁定机制。但重点是,您只需要确保以线程安全方式访问数据。

  

在闭包内(对于任务完成处理程序)进行dispatch_async调用是否会导致任何问题?

答案是否定的。只要您确保在这些闭包中不存在对self的引用,并且以线程安全方式访问/更改竞争线程可访问的数据。