从 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 检查空数组的主要内容,如果未能解决你的问题,请参考以下文章