2016-04-19 3 views
1

Ich ziehe derzeit Daten über Twitter Search API.Wie JSON-Daten ordnungsgemäß analysiert werden, wenn einige Daten NSNull sind

Sobald ich die Daten erhalte, versuche ich die Daten zu analysieren und in meine TweetDetails-Klasse zu speichern (die den Namen des Autors, die URL des Profilbilds, den Text des Tweets und den Ort des Tweets enthält) , die Tweet-ID und die Benutzer-ID).

In einigen Fällen haben die Tweets keinen Speicherort (ich denke, es hat etwas zu tun, wenn sie retweeted sind) und das bestimmte Wörterbuch (hier tweetsDict ["place"]), die sonst diese Informationen enthalten würde , gibt stattdessen NSNull zurück.

Bei diesen Gelegenheiten, erhalte ich diese Störung

nicht Wert vom Typ werfen kann 'NSNull' (0x1093a1600) auf 'NSDictionary' (0x1093a0fe8).

Hier ist mein Code wie ich versuche, um die Daten zu analysieren und sie zu Objekten in meiner TweetDetails Klasse speichern

client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in 
     if connectionError != nil { 
      print("Error: \(connectionError)") 
     } 
     do { 
      let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) 

      if let tweets = json["statuses"] as? [NSDictionary] { 
       for tweetsDict in tweets { 
        let text = tweetsDict["text"] as! String 
        let tweetID = tweetsDict["id_str"] as! String 
        let place = tweetsDict["place"] as! NSDictionary 

        // this line ^^ is where the error occurs 
        let city = place.valueForKey("full_name") 
        let user = tweetsDict["user"] as! NSDictionary 
        let userID = user.valueForKey("id_str") 
        let screenName = user.valueForKey("screen_name")! 
        let avatarImage = user.valueForKey("profile_image_url_https")! 

        let tweet = TweetDetails(authors: screenName as! String, profileImages: avatarImage as! String, tweetTexts: text, tweetLocations: city as! String , tweetIDs: tweetID , userIDs: userID as! String) 
        self.allTweets.append(tweet) 
        self.tweetTableView.reloadData() 
       } 
      } 
     } catch let jsonError as NSError { 
      print("json error: \(jsonError.localizedDescription)") 
     } 
    } 

habe ich versucht, einige ‚if-let‘ Aussagen zu erstellen Alternativen zu bieten diese Anlässe, aber nichts hat funktioniert.

Könnte mir bitte jemand helfen, eine benutzerdefinierte Alternative zu erstellen, wenn bestimmte JSON-Daten als NSNull zurückgegeben werden. (Sogar etwas so einfaches wie das Umdrehen meiner "city" -Variable in die Zeichenfolge "Unbekannter Ort" in den Fällen, in denen die Daten NSNull zurückgeben).

Vielen Dank im Voraus und bitte lassen Sie mich wissen, wenn es noch etwas gibt, was ich hinzufügen kann, um mehr Klarheit zu dieser Frage zu geben.

+0

Kurz gesagt, verwenden Sie niemals das erzwungene Casting von 'as!', Es sei denn, Sie wissen, dass der Wert niemals 'nil' sein kann. Wenn ein Verbindungsfehler vorliegt, stürzt dieser Code ab (weil 'data' möglicherweise" nil "ist und Sie eine erzwungene Entpackung durchführen). Vielleicht fügen Sie in dieser Klausel eine 'return'-Anweisung ein, in der Sie die Fehlermeldung ausgeben (oder' guard' verwenden), so dass Sie im Falle eines Fehlers nicht 'JSONObjectWithData' mit' data! 'Ausführen. – Rob

Antwort

2

Wie andere haben darauf hingewiesen, können Sie optional verwenden Bindung (if let) oder, in diesem Fall noch einfacher, nur optional Verkettungs beschäftigen:

let city = tweetsDict["place"]?["full_name"] as? String 

diese Weise ist city eine optionale , dh wenn kein Wert gefunden wurde, weil kein place oder full_name Eintrag vorhanden war, wird es nil sein.

Es würde jedoch scheinen, dass Ihre TweetDetailscity zu einem String zwingen wird. Benötigt es unbedingt eine Stadt? Es wäre am besten, diese Methode zu ändern, so dass city optional war und nil Werte dort problemlos verarbeitet. Alternativ können Sie die Werte nil für city durch eine andere Zeichenfolge ersetzen, z.mit den nil Koaleszierstruktur Betreibern:

let city = tweetsDict["place"]?["full_name"] as? String ?? "Unknown city" 

, dass die Stadt zurück, wenn gefunden, und „Unknown Stadt“, wenn nicht.

+1

Danke Rob, das hat das unmittelbare Problem definitiv behoben. Danke auch @ZGski und AntoineLamy, deine Beiträge werden mir helfen, das alles in Zukunft besser zu machen ... – DrMac

0

Ich sehe eine Menge von Force-Daten-Casting in Ihrem Code Hexe ist sehr gefährlich, vor allem bei der Analyse von JSON. Der richtige Umgang mit der NULL-Fähigkeit besteht darin, sie nicht zu vermeiden, indem wir versuchen, dasselbe zu tun, was wir in Ziel-c getan haben, sondern uns darauf vorzubereiten, NULL zu erhalten und dementsprechend zu reagieren. Dein Datenmodell sollte die Tatsache darstellen, dass ein Tweet manchmal keinen Standort hat, daher sollten einige Eigenschaften von TweetDetails als Optionals markiert werden.

Das folgende Code-Beispiel ist vollständig ungetestet, gibt Ihnen jedoch eine Vorstellung davon, wie Ihr Code aussehen kann, wenn er mit Null-Fähigkeit arbeitet.

client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in 
    if connectionError != nil { 
     print("Error: \(connectionError)") 
    } 
    do { 
     let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) 
    if let tweets = json["statuses"] as? [[String: AnyObject]] { 
     for tweetsDict in tweets { 
      if let text = tweetsDict["text"] as? String, 
      tweetID = tweetsDict["id_str"] as? String { 

       var city: String? 
       if let place = tweetsDict["place"] as? [String: AnyObject] { 
        city = place.valueForKey("full_name") 
       } 

       var userID: String? 
       var screenName: String? 
       var avatarImage: String? 
       if let user = tweetsDict["user"] as? [String: AnyObject] { 
        userID = user["id_str"] as? String 
        screenName = user["screen_name"] as? String 
        avatarImage = user["profile_image_url_https"] as? String 
       } 

       let tweet = TweetDetails(authors: screenName, profileImages: avatarImage, tweetTexts: text, tweetLocations: city, tweetIDs: tweetID, userIDs: userID) 
       self.allTweets.append(tweet) 
      } 
     } 
     self.tweetTableView.reloadData() 
    } 
} catch let jsonError as NSError { 
    print("json error: \(jsonError.localizedDescription)") 
    } 
} 
+0

Dies funktioniert nicht, weil Sie "city" innerhalb des Bereichs der optionalen Bindungsklausel definiert haben, aber danach in 'TweetDetails' aufgerufen werden müssen. – Rob

+0

Sie haben Recht @Rob, ich habe meine Antwort entsprechend geändert, aber der eigentliche Code hier ist nicht wirklich wichtig, es geht eher um die korrekte Art der Handhabung der Nullität. Wenn ein Wert gleich null sein kann, bedeutet dies, dass er in der Modellklasse als optional deklariert werden sollte, anstatt alles auszupacken. Im Beispiel sollte die Eigenschaft 'city' im Objekt' TweetDetails' als 'let city: String?' Deklariert werden. –

Verwandte Themen