2017-06-20 4 views
-1

Ich habe eine Klasse erstellt, wie im folgenden Code gezeigt, und wie Sie sehen können, analysiere ich eine JSON-Datei in der Klasse außerhalb der ViewController.Warte auf JSON-Analyse in einer anderen Klassendatei in swift 3

Wenn ich das AllCards-Objekt im View-Controller erzeuge, gebe ich offensichtlich 0 zurück, aber nach einer Weile gibt es die korrekte Anzahl an Karten zurück.

hier meine Fragen:

1) Wie kann ich die Objekterstellung vor dem viewDidLoad warte so auf der Ansicht, die das AllCard Objekt hat lud die richtige Anzahl von Karten wird zurückkehren?

2) Wenn ich eine Schaltfläche im ViewController hinzufüge und die Anzahl der Karten aktualisiere, friert es ein, bis alle Karten erstellt sind. Ich denke, weil in meinem Code alles in der Hauptwarteschlange ist. Wie kann ich das auflösen?

3) Ist es eine gute Übung, JSON in einer separaten Klasse wie ich zu analysieren?

allcards Klasse:

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

-View-Controller:

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

* Fragen Sie nicht, sagen *. Da Sie nur eine einzige Aufgabe haben, ist eine Versandgruppe nutzlos.Verwenden Sie einen Beendigungshandler, um den Aufrufer zu informieren, dass das Herunterladen und Parsen abgeschlossen ist. Verwenden Sie einen dedizierten Hintergrundthread, um das Einfrieren zu vermeiden, oder rufen Sie die Download-Aufgabe in einer separaten Funktion auf. – vadian

+0

Wie kann ich das tun? – aspnet82

+0

Es gibt Hunderte von Fragen hier auf SO zum Beispiel suchen Sie bitte https://stackoverflow.com/search?q=%5Bswift%5D+completion+handler – vadian

Antwort

0

1), wenn Sie ein Objekt über einen UIStoryboard segue passieren, es vor viewDidLoad() Set aufgerufen wird. Wenn Sie jedoch darauf warten möchten, dass die Oberflächenelemente bereit sind, gehe ich normalerweise auf das Element didSet. Sie könnten eine guard-Anweisung hinzufügen, um Ihr Objekt dort zu überprüfen, wenn Sie möchten.

2) vor allem werden Sie wahrscheinlich eine Schließung so vielleicht lesen 3) zuerst. Sie verwenden dispatchGroup.enter() hier, DispatchQueue.global.async { } ist der übliche Weg, um das zu erreichen, was Sie tun. Fügen Sie in einem DispatchQueue.main.async { }, wenn Sie wollen, oder tauchen Sie in den Haupt-Thread in der View-Controller, bis zu Ihnen wirklich. Schauen Sie sich die Unterschiede zwischen [unowned self] und [weak self] an, wenn Sie Zeit haben.

3) Geben Sie Ihrem Card Objekt einen init(from: JSON) Initialisierer, wo es seine Eigenschaften vom JSON-Objekt analysiert, das Sie übergeben. Lassen Sie die für den Download verantwortliche Funktion (Alamofire in Ihrem Fall) in einer anderen Klasse leben (wie zum Beispiel APIClient) und geben Sie eine Download-Funktion mit einer Schließung in der Argumentliste wie completion: ((JSON?) ->())? zurück, um das JSON Objekt zurückzugeben. Lassen Sie diese Klasse ein JSON-Objekt herunterladen und initialisieren Sie dann Ihr Card Objekt mit dem init(from: JSON) Initialisierer, den Sie zuvor geschrieben haben. Beachten Sie, dass dies kein Ansatz ist, der für Core Data NSManagedObjects geeignet ist. Wenn Sie also lokalen Speicher benötigen, sollten Sie dies berücksichtigen.

Am Ende sollten Sie in der Lage sein, eine Reihe von Karten, so etwas zu bauen:

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

Hier ist ein Beispiel für Abschluss-Handler. Zuerst Sie haben eine Funktion in einer einzigen Klasse ex schreiben: APICall

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

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

und diese Methode aus jeder Klasse aufrufen.

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