简体   繁体   中英

URLSession.shared.dataTask freezes the UI

I am making a Swift app for iOS and I have an issue on a request I make.

This request is made every 3 to 5 seconds and the body is a 5k lines JSON (~130k characters in total) that refreshes a UITableView . The issue is that every time .dataTask is used on this specific request, the app freezes then runs normally after the request has been made.

By "freezes" I mean that I've detected it when I scroll my long UITableView. Even a small scroll list freezes.

I first suspected the update of the UITableView , but I added a small 'hack' that disables the update of the UITableView when scrolling, like this:

    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        print("started scrolling")
        self.currentlyScrolling = true
    }

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        print("stopped scrolling")
        self.currentlyScrolling = false
    }

It doesn't work.

My question is then: I think that dataTask is NOT run in the main thread. But I am not sure. How can I check it? Also, how can I be sure that dataTask is async ?

Here's what the dataTask code looks like:

let task = URLSession.shared.dataTask(with: req) { data, response, err in
        guard let data = data, err == nil else {
            // error
            return
        }

        if let resp = try? JSONSerialization.jsonObject(with: data) {
            // success
        }
    }

    task.resume()

Little note however, it ONLY freezes BEFORE the JSONSerialization, not after, so I guess it is not what it is causing the freeze.

URLSession.shared.dataTask runs in background thread, you can move the JSONSerialization and if you are updating the UI move that all in main thread

let task = URLSession.shared.dataTask(with: req) { data, response, err in {

    // HERE YOU ARE IN BACKGROUND THREAD, see print result in debug area

    print("You are on \(Thread.isMainThread ? "MAIN" : "BACKGROUND") thread.")

    guard let data = data, err == nil else { return }

    if let resp = try? JSONSerialization.jsonObject(with: data) {
        DispatchQueue.main.async {
            print("Now moved to \(Thread.isMainThread ? "MAIN" : "BACKGROUND") thread")

            // success, ANY UI UPDATES MUST BE MADE HERE
        }
    }
}

Your JSON parsing should be on the background thread, so this parsing operation will not block other things, such as the UI, on the main thread.

Following is an example that uses a completion block that is called on main thread

func myApiTask(with request: URLRequest, completion:@escaping (_ data: Any?) -> Void) {
    let task = URLSession.shared.dataTask(with: request) { data, response, error in

        var resp: Any?
        defer {
            DispatchQueue.main.async{ completion(resp) }
        }

        if data == nil && error == nil {
            resp = try? JSONSerialization.jsonObject(with: data!)
        } else {
            // error handling
        }

    }
}

Usage

myApiTask(with: req) { data in
    // you are on main thread
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM