2016-04-19 2 views
1

現在、Twitterの検索APIを使用してデータを取得しています。一部のデータがNSNullの場合、JSONデータを正しく解析する方法

データを受け取ったら、私のTweetDetailsクラス(著者の名前、プロフィールのURL、ツイートのテキスト、ツイートの場所を保持するためのデータ)を解析して保存しようとしています、ツイートIDとユーザーID)。

場合によっては、ツイートには場所がありません(リッツウィジェットであれば何かしていると思います)。それ以外の場合はtweetsDict ["place"] NSNullを返します。これらの機会に

、私はこのエラー

は、型の値をキャストすることができませんでした受信 'nsnullを'(0x1093a1600) 'NSDictionaryの'(0x1093a0fe8)には。ここで

私は私のTweetDetailsクラス内のデータを解析してオブジェクトに保存し

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

をしようとしていますように私はのための選択肢を提供するために、いくつかの「IF-レッツ文を作成しようとした私のコードですこれらの機会は、しかし何も働いていない。

特定のJSONデータがNSNullとして返されたときに、別の方法でカスタム代替案を作成してもらえますか? (データがNSNullを返す場合は、「都市」変数を文字列「Unknown Location」に変換するだけの簡単なことです)。

ご質問ありがとうございます。この質問をより明確にするために追加できるものがある場合は、お知らせください。

+0

要するに、値が 'nil'にならないことが分かっていない限り、' as! 'の強制的なキャストは絶対に使用しないでください。また、接続エラーが発生した場合、このコードはクラッシュします( 'data'は' nil 'なので、強制アンラッピングを実行するため)。おそらく、エラーメッセージが表示される(または 'guard'を使用する)節に' return'ステートメントを挿入してください。エラーがあった場合、 'data! 'を使って' JSONObjectWithData'を実行しないでください。 – Rob

答えて

2

他の人が指摘したように、あなただけのオプションのチェーンを採用し、さらに簡単に、この場合には、(if let)バインディングのオプションを使用するか、またはすることができます

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

この方法で、cityはオプションですすなわち、placeまたはfull_nameのエントリがないために値が見つからない場合は、nilになります。

TweetDetailsは、強制的にキャストすると表示されます。cityからStringです。それは絶対に都市を必要としますか? cityがオプションで、適切にnilの値を扱うように、この方法を変更することをお勧めします。代わりに、のnil値を他の文字列に置き換えることもできます。

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

ない場合は、見つかった場合、市内を返し、「不明な都市」:nil合体演算子を持ちます。

+1

おかげでRob、これは間違いなく直ちに問題を解決しました。また、@ ZGskiとAntoineLamyに感謝します。あなたの投稿は、今後これをもっとうまく設定する方法を教えてくれるでしょう... – DrMac

0

あなたのコードの魔法使いに力のデータ型のキャストがたくさんあるのは、特にJSONの解析時に非常に危険です。 null可能性を扱う正しい方法は、私たちがobjective-cで行ったのと同じことをやろうとするのではなく、それを受けずにそれに応じて対応することで回避することではありません。あなたのデータモデルは、ある時点でツイートに場所がないので、TweetDetailsのいくつかのプロパティをオプションとしてマークする必要があるという事実を表すべきです。

コード例は完全にテストされていませんが、あなたのコードがnull値を扱うように見えるかどうかを知ることができます。

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

これはオプションのbinding節のスコープの中に 'city'を定義したので動作しませんが、' TweetDetails'呼び出しの後で 'city'が必要になります。 – Rob

+0

あなたは正しいです@ロブ、私はそれに応じて私の答えを変更しましたが、ここでの実際のコードは本当に重要ではない、それはnullabilityを処理する正しい方法についてです。ある値にnilを指定することができれば、すべての値をアンラップするのではなく、モデルクラスでオプションとして宣言する必要があることを意味します。例では、プロパティ 'city'は' TweetDetails'オブジェクトの 'let city:String?'として宣言されるべきです。 –

関連する問題