我是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
}
答案 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
}
}