2016-04-19 4 views
1

В настоящее время я извлекаю данные через API поиска в Twitter.Как правильно проанализировать данные JSON, если некоторые данные NSNull

Как только я получаю данные, я пытаюсь разобрать и сохранить данные в свой класс TweetDetails (который должен содержать имя автора, URL-адрес их профиля pic, текст твита, расположение твита , идентификатор твита и идентификатор пользователя).

В некоторых случаях у твитов нет местоположения (я думаю, что ему нужно что-то делать, если они перепутаны) и определенный словарь (здесь есть твитыDict ["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)") 
     } 
    } 

Я попытался создать несколько «если давайте заявления для предоставления альтернативы эти случаи, но ничего не сработало.

Может ли кто-нибудь помочь мне создать пользовательскую альтернативу, когда некоторые данные JSON возвращаются как NSNull. (Даже что-то так же просто, как превратить переменную «город» в строку «Неизвестное местоположение» в тех случаях, когда данные возвращаются NSNull).

Заранее благодарим за участие и прошу сообщить, если есть что-то еще, что я могу добавить, чтобы предоставить более ясность в этом вопросе.

+0

Короче говоря, никогда не используйте принудительное литье 'as!', Если вы не знаете, что значение никогда не может быть «nil». Кроме того, если есть ошибка соединения, этот код сработает (потому что 'data' может быть' nil', и вы приступаете к принудительной разворачиванию его). Возможно, вставьте предложение 'return' в этом разделе, где вы печатаете сообщение об ошибке (или используйте' guard'), так что если произошла ошибка, вы не будете запускать 'JSONObjectWithData', используя' data! '. – Rob

ответ

2

Как уже отмечалось, вы можете использовать опциональный связывания (if let), или, в данном случае, даже проще, просто использовать опциональный цепочки:

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

Таким образом, city является необязательным , т. е. если значение не было найдено, потому что не было place или full_name, оно будет nil.

Похоже, что ваш TweetDetails является принудительным литьем city на String. Это абсолютно необходимо для города? Было бы лучше всего изменить этот метод, чтобы city был необязательным и грациозно обрабатывал nil значений. В качестве альтернативы вы можете заменить nil значениями для city на некоторую другую строку, например.с оператором nil коалесцирующим:

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

Это возвращает город, если найдено, и «Неизвестными городами», если нет.

+1

Спасибо, Роб, это определенно определило ближайшую проблему. Кроме того, спасибо @ZGski и AntoineLamy, ваши сообщения помогут мне в том, как лучше настроить все это в будущем ... – DrMac

0

Я вижу, что в вашем коде очень много типов данных о силе, очень опасно, особенно при разборе JSON. Правильный способ борьбы с недействительностью заключается не в том, чтобы избежать этого, пытаясь сделать то же самое, что и мы в объективе-c, но подготовить к получению нулевого и реагировать соответствующим образом. Ваша модель данных должна представлять тот факт, что когда-то твит не имеет места, поэтому некоторые свойства 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? [[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

Это не сработает, потому что вы определили 'city' внутри области необязательного предложения привязки, но это необходимо после этого в' TweetDetails'. – Rob

+0

Вы правы @Rob, я изменил свой ответ соответственно, но фактический код здесь не очень важен, это скорее правильный способ обращения к nullability. Если какое-либо значение может быть равно nil, это означает, что он должен быть объявлен как необязательный в классе модели, а не для вскрытия всего. В качестве примера, свойство 'city' должно быть объявлено как' let city: String? 'В объекте' TweetDetails'. –

Смежные вопросы