2017-06-20 7 views
-1

私は下のコードのようにクラスを作成しましたが、私はviewControllerの外のクラスでJSONファイルを解析していることがわかります。すぐに別のクラスファイルでJSON解析を待つ3

View ControllerでAllCardsオブジェクトを作成すると、明らかに最初は0が返されますが、しばらくすると正しいカード数が返されます。ここ

私の質問:

1)AllCardオブジェクトをロードしたビューは、カードの正しい数を返しますのように、私はのviewDidLoad前にオブジェクトの作成を待つことができますどのように?

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

* tell *、*を入力しないでください。あなたは** **一つの**仕事しか得ていないので、ディスパッチグループは役に立たない。完了ハンドラを使用して、ダウンロードと解析が完了したことを発信者に通知します。フリーズを避けるために専用のバックグラウンドスレッドを使用するか、別の機能でダウンロードタスクを呼び出します。 – vadian

+0

どうすればいいですか? – aspnet82

+0

何百もの関連する質問がありますので、https://stackoverflow.com/search?q=%5Bswift%5D+completion+handlerを検索してください。 – vadian

答えて

0

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) 
    } 
} 
2

は完了ハンドラの一例です。 まず、単一のクラスの元に関数を記述する必要があります。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) 
}) 
関連する問題