从 JSON 检查空数组

Posted

技术标签:

【中文标题】从 JSON 检查空数组【英文标题】:Check For Empty Array From JSON 【发布时间】:2016-05-27 13:54:43 【问题描述】:

我试图从 JSON 中获取一个字符串数组,并且我试图弄清楚如果返回的数组是空的如何处理它。在某些情况下,返回值为 [],而在其他情况下,数组包含字符串值。由于意外找到 nil 值而崩溃。

为澄清起见,gyms 数组是从另一个类传递的,这里的所有内容都可以在没有图像代码的情况下运行。

这是我的相关代码:

var gyms = [AnyObject]()
var imageArrays = [[String]?]()

在 viewDidLoad() 中

getGymImages()

获取JSON数据的方法:

func getGymImages() 
        var index = 0

        for dictionary in gyms 
            let id = dictionary["id"] as! String

            let urlString = String("https://gyminyapp.azurewebsites.net/api/GymImage/\(id)")
            let url = NSURL(string: urlString)
            let data = NSData(contentsOfURL: url!)

            do 
                let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
                for imageArray in json as! [AnyObject] 
                    imageArrays.append((imageArray as? [String])!)
                
             catch 
                print("Error")
            

            index += 1
        

        addImagesToGyms()
    

    func addImagesToGyms() 
        var index = 0;

        for array in imageArrays 
            var dictionary = gyms[index] as! [String:AnyObject]
            dictionary["images"] = array
            gyms[index] = dictionary

            index += 1
        
    

在 cellForRowAtIndexPath() 中

let gymImages = dictionary["images"] as! [String]
        if gymImages.count > 0 
            let firstImageURL = gymImages[0] as String
            cell.cellImageView.sd_setImageWithURL(NSURL(string: firstImageURL))
        

编辑:我被要求显示更多文件,所以在这里。

import UIKit

class GymListTableViewController: UITableViewController 

    var gyms = [AnyObject]()
    var gymName: String?
    var gymAddress: String?
    var gymPhoneNumber: String?
    var gymWebsite: String?
    var gymID: String?
    var gymLatitude: String?
    var gymLongitude: String?
    var maxDistance: Double?
    var myLocation: CLLocation?
    var milesArray = [Double]()
    var imageArrays = [[String]?]()

    var segmentedControl: UISegmentedControl?

    override func viewDidLoad() 
        super.viewDidLoad()

        self.title = "Gyms"

        tableView.registerNib(UINib(nibName: "GymListTableViewCell", bundle: nil), forCellReuseIdentifier: "gymCell")

        self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "waypoint_map"), style: .Done, target: self, action: #selector(showMapView))
        self.navigationItem.rightBarButtonItem?.tintColor = BarItems.greenTintColor

        segmentedControl = UISegmentedControl(items: ["A-Z", "Z-A", "Rating", "Distance"])
        segmentedControl?.sizeToFit()
        segmentedControl?.selectedSegmentIndex = 0
        segmentedControl!.setTitleTextAttributes([NSFontAttributeName: UIFont(name:"Helvetica-Light", size: 15)!],
                                       forState: UIControlState.Normal)
        segmentedControl?.addTarget(self, action: #selector(changeSelectedSegmentIndex), forControlEvents: .ValueChanged)
        self.navigationItem.titleView = segmentedControl

        sortAlphabetically()

        let backgroundImage = UIImage(named: "gray_background")
        let backgroundImageView = UIImageView(image: backgroundImage)
        tableView.backgroundView = backgroundImageView

        addDistancesToGyms()
        getGymImages()

        // geocodeAddresses()
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    

    func addDistancesToGyms() 
        var index = 0

        for distance in milesArray 
            var dictionary = gyms[index] as! [String:AnyObject]
            dictionary["distance"] = distance

            gyms[index] = dictionary

            index += 1
        
    

    func getGymImages() 
        var index = 0

        for dictionary in gyms 
            let id = dictionary["id"] as! String

            let urlString = String("https://gyminyapp.azurewebsites.net/api/GymImage/\(id)")
            let url = NSURL(string: urlString)
            let data = NSData(contentsOfURL: url!)

            do 
                let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
                for imageArray in json as! [AnyObject] 
                    imageArrays.append((imageArray as? [String])!)
                
             catch 
                print("Error")
            

            index += 1
        

        addImagesToGyms()
    

    func addImagesToGyms() 
        var index = 0;

        for array in imageArrays 
            var dictionary = gyms[index] as! [String:AnyObject]
            dictionary["images"] = array
            gyms[index] = dictionary

            index += 1
        
    

    func changeSelectedSegmentIndex() 
        let segmentTouched = segmentedControl?.selectedSegmentIndex

        if segmentTouched == 0 
            sortAlphabetically()
         else if segmentTouched == 1 
            sortReverseAlphabetically()
         else if segmentTouched == 2 
            sortByRatingAscending()
         else 
            sortByDistanceAscending()
        
    

    func sortAlphabetically() 
        gyms.sortInPlace
            (($0 as! Dictionary<String, AnyObject>)["name"] as? String) < (($1 as! Dictionary<String, AnyObject>)["name"] as? String)
        

        tableView.reloadData()
    

    func sortReverseAlphabetically() 
        gyms.sortInPlace
            (($0 as! Dictionary<String, AnyObject>)["name"] as? String) > (($1 as! Dictionary<String, AnyObject>)["name"] as? String)
        

        tableView.reloadData()
    

    func sortByRatingAscending() 
        // TODO: Sort by rating
    

    func sortByDistanceAscending() 
        gyms.sortInPlace
            (($0 as! Dictionary<String, AnyObject>)["distance"] as? Double) < (($1 as! Dictionary<String, AnyObject>)["distance"] as? Double)
        

        tableView.reloadData()
    

    func showMapView() 
        self.performSegueWithIdentifier("displayMapSegue", sender: self.navigationController)
    

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int 
        return 1
    

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return gyms.count
    

    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat 
        return 131
    

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCellWithIdentifier("gymCell", forIndexPath: indexPath) as! GymListTableViewCell

        let dictionary = gyms[indexPath.row]
        let addressDictionary = dictionary["address"]
        let street = addressDictionary!!["streetAddress"] as! String
        let city = addressDictionary!!["city"] as! String
        let state = addressDictionary!!["state"] as! String

        let zipInt = addressDictionary!!["zipCode"] as! Int
        let zipCode = String(zipInt)

        let addressString = String("\(street) " + "\(city), " + "\(state) " + "\(zipCode)")

        cell.backgroundColor = UIColor.clearColor()
        cell.gymNameLabel.text = dictionary["name"] as? String
        cell.gymAddressLabel.text = addressString

        let miles = dictionary["distance"] as! Double
        let milesString = String(format: "%.1f miles", miles)
        let milesLabelString = milesString
        cell.milesLabel.text = milesLabelString

        let gymImages = dictionary["images"] as! [String]
        if gymImages.count > 0 
            let firstImageURL = gymImages[0] as String
            cell.cellImageView.sd_setImageWithURL(NSURL(string: firstImageURL))
        

        return cell
    

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 
        let dictionary = gyms[indexPath.row]

        if dictionary["name"] as? String != nil 
            self.gymName = dictionary["name"] as? String
        

        let cell = tableView.cellForRowAtIndexPath(indexPath) as! GymListTableViewCell
        self.gymAddress = cell.gymAddressLabel.text

        if dictionary["phone"] as? String != nil 
            self.gymPhoneNumber = dictionary["phone"] as? String
        

        if dictionary["website"] as? String != nil 
            self.gymWebsite = dictionary["website"] as? String
        

        if dictionary["id"] as? String != nil 
            self.gymID = dictionary["id"] as? String
        

        if dictionary["latitude"] as? String != nil 
            self.gymLatitude = dictionary["latitude"] as? String
        

        if dictionary["longitude"] as? String != nil 
            self.gymLongitude = dictionary["longitude"] as? String
        

        self.performSegueWithIdentifier("detailFromListSegue", sender: self.navigationController)
    

    // MARK: - Navigation

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 
        if segue.identifier == "detailFromListSegue" 
            let gymDetailVC = segue.destinationViewController as! DetailTableViewController
            if self.gymName != nil 
                gymDetailVC.gymName = self.gymName
             else 
                gymDetailVC.gymName = nil
            

            if self.gymAddress != nil 
                gymDetailVC.gymAddress = self.gymAddress
             else 
                gymDetailVC.gymAddress = nil
            

            if self.gymPhoneNumber != nil 
                gymDetailVC.gymPhoneNumber = self.gymPhoneNumber
             else 
                gymDetailVC.gymPhoneNumber = nil
            

            if self.gymWebsite != nil 
                gymDetailVC.gymWebsite = self.gymWebsite
             else 
                gymDetailVC.gymWebsite = nil
            

            if self.gymID != nil 
                gymDetailVC.gymID = self.gymID!
             else 
                // gymDetailVC.gymID = nil
            

            if self.gymLatitude != nil 
                gymDetailVC.gymLatitude = self.gymLatitude!
            

            if self.gymLongitude != nil 
                gymDetailVC.gymLongitude = self.gymLongitude!
             
        
    

【问题讨论】:

你在什么时候因为意外的 nil 而崩溃?在你的cellForRowAtIndexPath? 它在 getGymImages() 中崩溃,在将值分配给 id 之后。 看起来您在任何时候都没有向gyms 附加任何内容。 for dictionary in gyms 肯定不会做任何事吗? gyms 数组是从另一个类传递过来的。这一切都可以在没有图像代码的情况下工作。 抱歉,只是为了确认一下——由于这一行,它返回了意外的 nil:let id = dictionary["id"] as! String 如果是这样,那么字典不包含键为“id”的记录 【参考方案1】:

numberOfRowsInSection 应该返回 gymImages.count(如果还没有的话)。

那么作为保障,你总是可以做到的

if indexPath.row < gymImages.count 


在访问cellForRowAtIndexPath中的内容之前

【讨论】:

它正在返回gyms.count 我们能看到更多的文件吗?

以上是关于从 JSON 检查空数组的主要内容,如果未能解决你的问题,请参考以下文章

如何从空嵌套对象和空数组中清除 json

如何从 iOS 中的 JSON 数组中删除空对象?

如何使用 JsonConvert 从包含空数组的 JSON 字符串中获取 DataTable?

使用 Json.NET (Newtonsoft) 将空数组从 JSON 转换为 XML

如何检查json数据数组是不是返回值

解析 json 数组在 swift 中返回空元素