2016-06-22 2 views
1

Ich habe ein TableView, das ich mit einer Liste von Elementen füllen möchte, die von einem Webdienst bereitgestellt werden. Der Service gibt ein JSON-Objekt mit Status (Erfolg oder Fehler) zurück und zeigt ein Array von Strings an.Wie erhalte ich einen Wert von einer NSURLSession-Aufgabe in eine Instanzvariable?

In viewDidLoad nenne ich die benutzerdefinierte Methode getShowsFromService()

func getShowsFromService() { 
    // Send user data to server side 
    let myURL = NSURL(string: "https://myurl.com/srvc/shows.php") 

    // Create session instance 
    let session = NSURLSession.sharedSession() 

    var json:NSDictionary = [:] 

    // Create the task 
    let task = session.dataTaskWithURL(myURL!) { //.dataTaskWithRequest(request) { 
     (data, response, error) in 

     guard let data = data else { 
      print("Error: \(error!.code)") 
      print("\(error!.localizedDescription)") 
      return 
     } 

     do { 
      json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as! NSDictionary 
     } catch { 
      print (error) 
     } 

     let sts = json["status"] as! NSString 
     print("\(sts)") 
    } 

    // Resume the task so it starts 
    task.resume() 

    let shows = json["shows"] as! NSArray 
    for show in shows { 
     let thisshow = show as! String 
     showsArray.append(thisshow) 
    } 

    // Here I get "fatal error: unexpectedly found nil while unwrapping an Optional value" 

} 

Das Verfahren empfängt das JSON-Objekt und setzt es in ein Wörterbuch. Dann möchte ich dieses Wörterbuch verwenden, um json ['show'] aufzurufen, um zu dem Array von Shows zu gelangen, die ich in einer Instanzvariable namens saysArray speichern möchte. Die Idee ist, showArray in tableView (cellForRowAtIndexPath) zu verwenden, um die Daten auszufüllen.

Das Problem ist, dass ich das Wörterbuch nicht in die Variable bekommen kann. Wenn ich versuche, es innerhalb der Aufgabe zu tun, erhalte ich einen Fehler, der besagt, dass ich self.showsArray aufrufen muss, und wenn ich das tue, gehen die Daten nicht in das Array. Wenn ich es außerhalb der Aufgabe mache, erhalte ich einen Fehler, weil es sagt, dass ich versuche, einen Nullwert auszupacken.

Wie kann ich das Wörterbuch erstellt innerhalb der Aufgabe in die ShowsArray var?

Antwort

0

Die Methode 'dataTaskWithURL' führt einen asynchronen Aufruf aus. Wenn Sie also task.resume() ausführen, springt sie zur nächsten Zeile und json ["show"] gibt null zurück, da das Wörterbuch zu diesem Zeitpunkt leer ist.

Ich würde empfehlen, diese Logik zu einem Abschluss-Handler irgendwo in Ihrer Klasse zu verschieben. Etwas entlang der Linien von:

func getShowsFromService() { 
    let myURL = NSURL(string: "https://myurl.com/srvc/shows.php") 
    let session = NSURLSession.sharedSession() 
    let task = session.dataTaskWithURL(myURL!, completionHandler: handleResult) 
    task.resume() 
} 

//-handle your result 
func handleResult(data: NSData?, response: NSURLResponse?, error: NSError?) { 
    guard let data = data else { 
     print("Error: \(error!.code)") 
     print("\(error!.localizedDescription)") 
     return 
    } 

    do { 
     if let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as! NSDictionary { 
      if let shows = json["shows"] as! NSArray { 
       //- this is still in a separate thread 
       //- lets go back to the main thread! 
       dispatch_async(dispatch_get_main_queue(), { 
        //- this happens in the main thread 
        for show in shows { 
         showsArray.append(show as! String) 
        } 
        //- When we've got our data ready, reload the table 
        self.MyTableView.reloadData() 
        self.refreshControl?.endRefreshing() 
       }); 
      } 
     } 
    } catch { 
     print (error) 
    } 
} 

Das Snippet oben als Richtschnur dienen soll (ich habe auf einen Spielplatz atm Zugang nicht).

Beachten Sie Folgendes: , sobald die Aufgabe (asynchron -> anderen Thread) vervollständigt wird es die neue Funktion handleResult aufrufen, die auf Fehler überprüfen, und wenn nicht, wird es den Dispatcher verwenden, um Ihre Aufgabe auszuführen der Hauptfaden. Ich gehe davon aus, dass ShowsArrays eine Klasseneigenschaft ist.

Ich hoffe, das

EDIT hilft:

Sobald Sie Ihre Daten abrufen, müssen Sie die Tabelle (aktualisierte Code oben) erneut zu laden. Sie können ein Aktualisierungssteuerelement verwenden (deklarieren Sie es als Klasseneigenschaft).

var refreshControl: UIRefreshControl! 

Dann, wenn Sie Ihre Daten fertig bekommen können Sie aktualisieren:

self.MyTableView.reloadData() 
self.refreshControl?.endRefreshing() 

dies Ihre Delegatmethoden nennen die Zeilen und Abschnitte zu füllen.

+0

Danke für die Hilfe Daniel. Ich habe versucht, den Code zu verwenden, aber wenn ich zu, wenn JSON NSJSONSerialization.JSONObjectWithData (Daten, Optionen: NSJSONReadingOptions()) wie erhalten! NSDictionary {Ich bekomme einen Fehler (Initialisierer für bedingte Bindung muss optionalen Typ haben, nicht NSDictionary). – cesarcarlos

+0

Ich habe es tatsächlich geschafft, diesen Teil zu reparieren und es geschafft, die Daten in die Klasseneigenschaft showSArray zu bekommen. Das Problem besteht nun darin, dass cellForRowAtIndexPath die Daten von diesem Array nicht lädt. Vielleicht, weil zum Zeitpunkt der Erstellung des Arrays CellForRowAtIndexPath bereits aufgerufen wurde? – cesarcarlos

+0

Gern geschehen!Ja, Sie können eine Reload-Tabellenmethode aufrufen, wenn Sie die Daten erhalten, so dass die Tabelle die aktualisierten Inhalte anzeigt, sobald dies geschieht. Ich werde die Antwort aktualisieren –

Verwandte Themen