加载本地JSON文件异步

时间:2018-05-08 14:02:29

标签: ios swift dispatch

我是swift的新手,也是加载文件的同步/异步方式。 我在本地有一个很大的JSON文件,一个关于足球的iPad应用程序,有足球运动员的名单和统计数据。

此刻,我将一系列播放器加载到一系列字典中 我让用户搜索特定的播放器

func loadJSON() {
    /// Load Json File
    if let path = Bundle.main.path(forResource: "players", ofType: "json") {
        do {
            let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)
            let jsonObj = try JSON(data: data)

            /// For Player in JSON Serialize values
            for (_,subJson):(String, JSON) in jsonObj["PackData"]["PlayerData"]["P"] {

                let firstName = subJson["_f"].stringValue
                let lastName = subJson["_s"].stringValue
                let id = subJson["_id"].stringValue
                let dateOfBirth = subJson["_d"].stringValue
                let height = subJson["_h"].stringValue
                let weight = subJson["_w"].stringValue
                let image = subJson["_i"].stringValue


                let player = Player(id: id, firstName: firstName, lastName: lastName, dateOfBirth: dateOfBirth, height: height, weight: weight, image: image)

                /// Append Player in players Array
                players.append(player)

            }

由于我在loadJSON()中使用ViewDidLoad,因此当我转到此视图时,应用会冻结几秒钟并占用大量内存。

在异步中处理/实现类似数据库搜索的正确方法是什么?

修改 我已尝试使用发送DispatchQueue.global(qos: .background).async,但我收到错误:indexPath.row out of range上的player = filteredPlayers[indexPath.row]

 // create a cell for each table view row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    // create a new cell if needed or reuse an old one

    let cell:UITableViewCell = self.searchTableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!
    let player: Player

    /// Return a different table if is searching or not
    if isFiltering() {
        player = filteredPlayers[indexPath.row]
    } else {
        player = players[indexPath.row]
    }
    cell.textLabel?.text = player.firstName! + " " + player.lastName!

    cell.textLabel?.textColor = UIColor.white

    return cell

}

3 个答案:

答案 0 :(得分:3)

您需要在后台的DispatchQueue中使用

func loadJSON() {
    /// Load Json File
    DispatchQueue.global(qos: .background).async{
        if let path = Bundle.main.path(forResource: "players", ofType: "json") {
            do {
                let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)
                let jsonObj = try JSON(data: data)

                /// For Player in JSON Serialize values
                for (_,subJson):(String, JSON) in jsonObj["PackData"]["PlayerData"]["P"] {

                    let firstName = subJson["_f"].stringValue
                    let lastName = subJson["_s"].stringValue
                    let id = subJson["_id"].stringValue
                    let dateOfBirth = subJson["_d"].stringValue
                    let height = subJson["_h"].stringValue
                    let weight = subJson["_w"].stringValue
                    let image = subJson["_i"].stringValue


                    let player = Player(id: id, firstName: firstName, lastName: lastName, dateOfBirth: dateOfBirth, height: height, weight: weight, image: image)

                    /// Append Player in players Array
                    players.append(player)

                }
            }
        }
    }
}

答案 1 :(得分:0)

  

转到后台线程进行长时间的工作

func loadJSON(_ completion:@escaping (_ jsonObj:JSON?) -> Void){
        DispatchQueue.global(qos: .background).async {
            if let path = Bundle.main.path(forResource: "players", ofType: "json") {
               if  let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped), let jsonObj = try? JSON.init(data: data){
                    completion(jsonObj)
               }else{
                 completion(nil)
                }
            }else{
                 completion(nil)
            }
        }
    }
  

然后像这样打电话

   self.loadJSON { (jsonObj) in

            DispatchQueue.main.async {
                guard let jsonObj = jsonObj else {return}
                /// For Player in JSON Serialize values
                for (_,subJson):(String, JSON) in jsonObj["PackData"]["PlayerData"]["P"] {

                    let firstName = subJson["_f"].stringValue
                    let lastName = subJson["_s"].stringValue
                    let id = subJson["_id"].stringValue
                    let dateOfBirth = subJson["_d"].stringValue
                    let height = subJson["_h"].stringValue
                    let weight = subJson["_w"].stringValue
                    let image = subJson["_i"].stringValue


                    let player = Player(id: id, firstName: firstName, lastName: lastName, dateOfBirth: dateOfBirth, height: height, weight: weight, image: image)

                    /// Append Player in players Array
                    players.append(player)
            }
        }

答案 2 :(得分:0)

您需要将冗长的任务调度到后台队列,并将结果发送回主队列。

我简化的json示例:

{
    "person": "Bob"
}

创建load json方法

func loadJSON(completion: @escaping (_ data: String?, _ error: Error?) -> ())  {
    var person: String?
    var receivedError: Error?

    /// Load json file and parse in background queue
    DispatchQueue.global(qos: .background).async {
        let path = Bundle.main.path(forResource: "myJSON", ofType: "json")!
        do {
            let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)
            let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
            let jsonDictionary =  json as! Dictionary<String, Any>

            person = jsonDictionary["person"] as? String
        } catch {
            receivedError = error
        }

        // Dispatch the found value to main queue
        DispatchQueue.main.async {
            completion(person, receivedError)
        }
    }
}

在你的代码中调用它:

loadJSON { (data, error) in
    if let retrievedData = data {
        print(retrievedData)
        // It is safe to assign the value to UI objects 
        // because the callback is on the main thread
    }
}