等待JSON在不同的类文件中快速解析3

等待JSON在不同的类文件中快速解析3

问题描述:

我创建了一个类,如下面的代码所示,并且您可以看到我正在解析viewController之外的类中的JSON文件。等待JSON在不同的类文件中快速解析3

当我在视图控制器中创建AllCards对象时,显然会在开始时返回0,但过了一段时间后它会返回正确数量的卡片。

在这里我的问题:

1)如何可以等待的对象创建的viewDidLoad中之前,所以在视图并加载AllCard对象将返回的卡是否正确? 2)如果我在viewController中添加一个更新卡片数量的按钮,它会冻结,直到所有的卡片都被创建。我想,因为在我的代码中,一切都在主队列中。我该如何解决这个问题?

3)像我一样在单独的类中解析JSON是否是一种很好的做法?

AllCards类:

import Foundation 
import Alamofire 
import SwiftyJSON 

class AllCards { 

var allCard = [Card]() 
let dispatchGroup = DispatchGroup() 
//gzt the JSON with Alamofire request 
let allCardsHTTP: String = "https://omgvamp-hearthstone-v1.p.mashape.com/cards?mashape" 
init() { 
    dispatchGroup.enter() 
    Alamofire.request(allCardsHTTP, method: .get).responseJSON { (response) in 
     if response.result.isSuccess { 
      let jsonCards : JSON = JSON(response.value!) 
      print("success") 
      //create the cards 
      if jsonCards["messagge"].stringValue != "" { 
       print(jsonCards["message"].stringValue) 
      } 
      else { 
       for (set, value) in jsonCards { 
        if jsonCards[set].count != 0 { 
         for i in 0...jsonCards[set].count - 1 { 
          let card = Card(id: jsonCards[set][i]["cardId"].stringValue, name: jsonCards[set][i]["name"].stringValue, cardSet: set, type: jsonCards[set][i]["type"].stringValue, faction: jsonCards[set][i]["faction"].stringValue, rarity: jsonCards[set][i]["rarity"].stringValue, cost: jsonCards[set][i]["cost"].intValue, attack: jsonCards[set][i]["attack"].intValue, durability: jsonCards[set][i]["durability"].intValue, text: jsonCards[set][i]["text"].stringValue, flavor: jsonCards[set][i]["flavor"].stringValue, artist: jsonCards[set][i]["artist"].stringValue, health: jsonCards[set][i]["health"].intValue, collectible: jsonCards[set][i]["collectible"].boolValue, playerClass: jsonCards[set][i]["playerClass"].stringValue, howToGet: jsonCards[set][i]["howToGet"].stringValue, howToGetGold: jsonCards[set][i]["howToGetGold"].stringValue, mechanics: [""], img: jsonCards[set][i]["img"].stringValue, imgGold: jsonCards[set][i]["imgGold"].stringValue, race: jsonCards[set][i]["race"].stringValue, elite: jsonCards[set][i]["elite"].boolValue, locale: jsonCards[set][i]["locale"].stringValue) 
          if jsonCards[set][i]["mechanics"].count > 0 { 
           for n in 0...jsonCards[set][i]["mechanics"].count - 1 { 
            card.mechanics.append(jsonCards[set][i]["mechanics"][n]["name"].stringValue) 
           } 
          } 
          else { 
           card.mechanics.append("") 
          } 
         self.allCard.append(card) 
         } 
        } 
        else { 
         print("The set \(set) has no cards") 
        } 
       } 
       print(self.allCard.count) 
      } 
     } 
     else { 
      print("No network") 
     } 
     self.dispatchGroup.leave() 
    } 
} 
} 

视图控制器:

import UIKit 

class ViewController: UIViewController { 
let allcards = AllCards() 
let mygroup = DispatchGroup() 

@IBAction func updateBtn(_ sender: Any) { 

    print(allcards.allCard.count) //Button is frozen until all the cards have been created then it shows the correct number of cards 

} 
override func viewDidLoad() { 
    super.viewDidLoad() 

    print(allcards.allCard.count)/This returns 0 

} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 


} 
+0

*不要问,告诉*。既然你只有**一个任务,一个派遣组是没用的。使用完成处理程序通知主叫方下载和分析已完成。并使用专用的后台线程来避免冻结或在单独的功能中调用下载任务。 – vadian

+0

我该怎么做? – aspnet82

+0

这里有数百个相关的问题,请搜索例如https://*.com/search?q=%5Bswift%5D+completion+handler – vadian

1)如果您是通过UIStoryboard赛格瑞传递一个对象,它是viewDidLoad()之前设置被调用。但是,如果您想等UI元素准备就绪,我通常会在UI元素上使用didSet,如果需要,您可以添加guard语句来检查您的对象。 2)首先,你可能会想要一个关闭,所以也许先读3)。你在这里使用dispatchGroup.enter()DispatchQueue.global.async { }是通常的方式来完成你在做什么。如果需要,可以在DispatchQueue.main.async { }中添加,或者在视图控制器中插入主线程,然后添加到真正的。当你有时间时,看看[unowned self][weak self]之间的差异。

3)给你的Card对象一个init(from: JSON)初始化器,它从你传递它的JSON对象中解析它的属性。 让负责下载的函数(在你的情况下为Alamofire)生活在不同的类中(例如APIClient),并在参数列表中给它一个带有闭包的下载函数,如completion: ((JSON?) ->())?返回JSON对象。让该类下载一个JSON对象,然后使用之前编写的init(from: JSON)初始值设定项初始化您的Card对象。请注意,这不适合与Core Data NSManagedObjects一起使用,因此如果您需要本地存储,请记住这一点。

到底,你应该能够建立的卡什么的数组是这样的:

APIClient.shared.fetchCards(completion: { cardJSONs in 
    let cards = [Card]() 
    for cardJSON: JSON in cardJSONs { 
     let card = Card(from; JSON) 
     cards.append(card) 
    } 
} 

下面是完成处理的一个例子。 首先,你必须写在一个类中的前一个函数:APICall

func getDataFromJson(allCardsHTTP: String, completion: @escaping (_ success: Any) -> Void) { 

    Alamofire.request(allCardsHTTP, method: .get).responseJSON { response in 
     if response.result.isSuccess { 
       completion(response) 
     } 
    } 
    } 

,并从任何类此方法。

let callApi = APICall() 
callApi.getDataFromJson(allCardsHTTP: "https://omgvamp-hearthstone-v1.p.mashape.com/cards?mashape",completion: { response in 
    print(response) 
})