在解析JSON数据期间在UITableView中滚动期间冻结

时间:2017-08-15 21:26:33

标签: ios json swift multithreading uitableview

我在新闻应用中遇到多线程问题。问题是 - 在我解析和加载数据之后滚动表视图时,我的应用程序经常冻结。我想我每次重新加载数据都是错误的。

第一部分:

final let urlString = "http://api.to.parse"

在这里,我创建了一系列结构来填充我的数据

struct jsonObjects {
        var id : Int
        var date : String
        var title : String
        var imageURL : URL

    }
    var jsonData = [jsonObjects]()

这是tableView的viewDidLoad

override func viewDidLoad() {
    super.viewDidLoad()
    // MARK : - Download JSON info on start

    JsonManager.downloadJsonWithURL(urlString: urlString, сompletion: {(jsonArray) -> Void in

        guard let data = jsonArray else { print("Empty dude"); return;}
        for jsonObject in data {

            if let objectsDict = jsonObject as? NSDictionary {

                guard   
                    let id = objectsDict.value(forKey: "id") as? Int,
                    let date = objectsDict.value(forKey: "date") as? String,
                    let titleUnparsed = objectsDict.value(forKey: "title") as? NSDictionary,
                    let title = (titleUnparsed as NSDictionary).value(forKey: "rendered") as? String,
                    let imageString = objectsDict.value(forKey: "featured_image_url") as? String,
                    let imageURL = NSURL(string: imageString) as URL?
                else {
                    print("Error connecting to server")
                    return
                }

在那里,我将填充结构附加到数组:

                self.jsonData.append(jsonObjects(id: id, date: date, title: title,
                                                 imageURL: imageURL))

            }

        }   
        DispatchQueue.main.async(execute: { 
            self.tableView.reloadData()
        })
    })

并且下载JsonWithURL只是:

class JsonManager {

class func downloadJsonWithURL(urlString: String, сompletion: @escaping (NSArray?) -> Void) {

    guard let url = NSURL(string: urlString) else { print("There is no connection to the internet"); return;}

    URLSession.shared.dataTask(with: url as URL, completionHandler: { (data, response, error) -> Void in

            guard let parseData = data else { print("There is no data"); return;}

                if let jsonObj = try? JSONSerialization.jsonObject(with: parseData, options: .allowFragments)
        as? NSArray {

                    сompletion(jsonObj)

                }

    }).resume()
}

最后 - 我在TableViewCell中输入了它:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return jsonData.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    guard let cell = tableView.dequeueReusableCell(withIdentifier: "newscell") as? NewsTableViewCell else {
        fatalError("Could not find cell by identifier")
    }

    guard let imageData = NSData(contentsOf: jsonData[indexPath.row].imageURL) else {
        fatalError("Could not find image")
    }

        cell.newsTitleLabel.text = self.jsonData[indexPath.row].title
        cell.newsTitleLabel.font = UIFont.boldSystemFont(ofSize: 20.0)
        cell.newsImageView.image = UIImage(data: imageData as Data)

    return cell
}

所以有两个问题:我应该如何分配我的线程以及如何调用它们以便我可以获得所有下载数据的流畅和漂亮的tableview?以及如何在单元格中重新加载数据?

2 个答案:

答案 0 :(得分:1)

你的问题是由imageData阻塞主线程引起的。解决此问题的最佳方法是将所有图像下载到图像缓存中。我肯定会从cellForRowAtIndexPath中删除图像下载。

答案 1 :(得分:0)

下载数据,在后台线程中解析,更新主线程上的UI。

基本上如果你这样做的话,一切都会好的。 因此,如果要在主线程上呈现UI,则可能需要再次检查一次。

在调试面板上,有暂停/播放按钮。 因此,无论何时冻结您的应用,请立即尝试暂停应用:

1)然后检查您的任何UI方法是否在后台线程上运行。

2)检查你的下载任务或解析json是否在主线程上进行。

如果属于上述情况,则需要正确。