【问题标题】:Display data from JSON in alphabetical sections in Table View in Swift在 Swift 的表格视图中按字母部分显示来自 JSON 的数据
【发布时间】:2017-07-03 02:42:11
【问题描述】:

我对 Xcode 和 Swift 还是很陌生。我正在尝试在 TableView 中按字母顺序显示数据(餐厅名称)。我有一个 JSON 文件,可以将每家餐厅分类到正确的社区。代码在视图控制器中完美运行,我在视图控制器中以部分的形式显示社区的名称,并在行中显示餐厅的名称。我的问题是我试图在不同的视图控制器中对所有餐厅名称进行排序,其中部分显示字母(A,B,C ...),并且在每个部分下,我试图按字母顺序显示餐厅,并在边。类似于 iPhone 上的联系人应用程序,但我需要显示餐厅名称的联系人姓名。希望我说得通。 我的代码如下所示:

class BarsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, SWRevealViewControllerDelegate, UISearchBarDelegate {


@IBOutlet var btnMenuButton: UIBarButtonItem!
@IBOutlet var tableView: UITableView!
@IBOutlet var searchButton: UIBarButtonItem!

var noDataLabel = UILabel()

let urlString = "http://barhoppersf.com/json/neighborhoods.json"

var restaurantArray = Array<Restaurant>()

var filteredRestaurants = [Restaurant]()

var shouldShowSearchResults = false

var searchBar = UISearchBar()
var logoImageView: UIImageView!

let restaurantsName = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","#"]
let indexName = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","#"]
let voidIndex = [""]


var restSections = [String]()
var restDictionary = [String : [String]]()

    override func viewDidLoad() {
    super.viewDidLoad()


    self.downloadJsonWithURL() // This loads tableview with data from url 

tableView.reloadData()
} 
   **//JSON FUNC**
func downloadJsonWithURL() {

    let url = NSURL(string: urlString)



    URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in

        if let error = error {

            print(error.localizedDescription)

            return
        }

        if let data = data {

            guard let json = try? JSONSerialization.jsonObject(with: data) else { return }

            guard let dict = json as? Dictionary<String,Dictionary<String,Dictionary<String,Array<Dictionary<String,String>>>>> else { return }

            guard let hoods = dict["hoods"] else { return }

            guard let names = hoods["neighborhoodNames"] else { return }

            for (key, value) in names {

                let neighborhood = NeighborhoodRestaurants(name: key, data: value)

                self.tableData.append(neighborhood)

                self.tableData.sort { $0.name < $1.name }

                self.filteredRestaurants = self.tableData


            }


            DispatchQueue.main.async {



                self.tableView.reloadData()
            }

        }

    }).resume()
}


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return self.restaurantArray[section].restaurants.count

}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {

    return self.restaurantArray[section].name
}

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    tableView.rowHeight = 40

    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! RestaurantsTableViewCell

    cell.barLabel.text = self.restaurantArray[indexPath.section].restaurants[indexPath.row].name


    return cell
}

我有一个单独的 swift 文件,其中包含 JSON 的所有结构

struct Restaurant {

var name: String
var cuisine: String
var hours: String
var description: String
var address: String
var phone: String
var website: String
var sports: String
var image: String



init?(dict:Dictionary<String,String>) {

    guard

        let name = dict["name"],
        let cuisine = dict["cuisine"],
        let hours = dict["hours"],
        let description = dict["description"],
        let address = dict["address"],
        let phone = dict["phone"],
        let website = dict["website"],
        let sports = dict["sports"],
        let image = dict["image"]


        else {
            return nil
    }

    self.name = name
    self.cuisine = cuisine
    self.hours = hours
    self.description = description
    self.address = address
    self.phone = phone
    self.website = website
    self.sports = sports
    self.image = image


}

//MARK: Function for the data from ViewControler
}

struct NeighborhoodRestaurants {

var name: String

var restaurants: Array<Restaurant>




init(name:String, data:Array<Dictionary<String,String>>) {

    self.name = name

    self.restaurants = Array<Restaurant>()

    for dict in data {

        if let restaurant = Restaurant(dict: dict) {

            self.restaurants.append(restaurant)

            self.restaurants.sort { $0.name < $1.name }

        }

    }
}

}

这是 JSON 文件:http://barhoppersf.com/json/neighborhoods.json

这是社区视图控制器的image,效果很好。你可以得到这个想法! 再次提前感谢!

【问题讨论】:

    标签: json swift uitableview


    【解决方案1】:

    我尝试使用一些不同的方法来解决您的问题。这是我制作的Sample
    这是我的控制器代码,并尝试根据 API 提供的数据使其类似于联系人应用程序。我只是在模型中取了餐厅名称,因为它只需要按字母顺序排序。所有其他细节和解释都在代码中的 cmets 中提及。

    import UIKit
    
    class ViewController: UIViewController {
        @IBOutlet weak var restaurantsTableView: UITableView!
    
        //The main array for tableView
        var dataArray = [(String,[Restaurant])]()
    
        var indexTitles = [String]()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            getData()
        }
    
        func getData() {
    
            let url = URL(string: "http://barhoppersf.com/json/neighborhoods.json")
            URLSession.shared.dataTask(with: url!) { (data, response, error) in
    
                guard let data = data else {return}
    
                let json = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [String : AnyObject]
    
                guard let hoods = json?["hoods"] else { return }
    
                guard let names = hoods["neighborhoodNames"] as? [String:[AnyObject]] else { return }
    
                self.makeDataSource(names: names)
    
                DispatchQueue.main.async {
                    self.restaurantsTableView.reloadData()
                }
            }.resume()
        }
    
        // The main logic for sorting and making the data like Contacts App tableView
        func makeDataSource(names:[String:[AnyObject]]) {
            //Temporary array to hold restaurants on different indexes
            var dict = [String:[Restaurant]]()
    
            //Character set taken to check whether the starting key is alphabet or any other character
            let letters = NSCharacterSet.letters
    
            for (_,value) in names {
                //Iterating Restaurants
                for resObj in value {
                    if let restaurantName = resObj["name"] as? String {
                        let restaurant = Restaurant(name: restaurantName)
                        var key = String(describing: restaurant.name.characters.first!)
    
                        key = isKeyCharacter(key: key, letters: letters) ? key : "#"
    
                        if let keyValue = dict[key] {
                            //Already value exists for that key
                            var filtered = keyValue
                            filtered.append(restaurant)
    
                            //Sorting of restaurant names alphabetically
                            filtered = filtered.sorted(by: {$0.0.name < $0.1.name})
                            dict[key] = filtered
                        } else {
                            let filtered = [restaurant]
                            dict[key] = filtered
                        }
                    }
                }
            }
            //To sort the key header values
            self.dataArray = Array(dict).sorted(by: { $0.0 < $1.0 })
    
            //Logic to shift the # category to bottom
            let temp = self.dataArray[0]
            self.dataArray.removeFirst()
            self.dataArray.append(temp)
    
            //For setting index titles
            self.indexTitles = Array(dict.keys.sorted(by: <))
    
            //Making the index title # at the bottom
            let tempIndex = self.indexTitles[0]
            self.indexTitles.removeFirst()
            self.indexTitles.append(tempIndex
        }
    }
    
    //Function to check whether key is alphabet or not
    func isKeyCharacter(key:String,letters:CharacterSet) -> Bool {
        let range = key.rangeOfCharacter(from: letters)
        if let _ = range {
            //Your key is an alphabet
            return true
        }
        return false
    }
    
    extension ViewController: UITableViewDataSource, UITableViewDelegate {
    
        func numberOfSections(in tableView: UITableView) -> Int {
            return dataArray.count
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return dataArray[section].1.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "RestaurantsTableCell") as! RestaurantsTableCell
            let restaurant = dataArray[indexPath.section].1[indexPath.row]
            cell.restaurantNameLabel.text = restaurant.name
            return cell
        }
    
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
            //Pass this model to detail VC
            let restaurant = dataArray[indexPath.section].1[indexPath.row]
    
            let detailVC = self.storyboard?.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
            detailVC.restaurant = restaurant
            self.navigationController?.pushViewController(detailVC, animated: true)
        }  
    
        func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
            return 30
        }
    
        func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
            return dataArray[section].0
        }
    
        //For index titles
        func sectionIndexTitles(for tableView: UITableView) -> [String]? {
            return self.indexTitles
        }
    }
    

    Restaurant 类现已分离。还修改了链接中的Sample,新建了DetailViewController类。

    import Foundation
    
    class Restaurant {
        var name = ""
    
        init(name:String) {
            self.name = name
        }
    }
    

    此代码可以在排序逻辑中进行改进。欢迎改进。

    这是输出:


    这里是细节控制器:

    【讨论】:

    • 拉詹,感谢您的帮助。我正在尝试用我拥有的代码来实现你的代码。我有一个 DetailViewController 显示餐厅的详细信息。那是来自我在单独的 swift 文件中的结构的调用。似乎代码现在停止了,但我正在尝试修复它。另外,有什么方法可以在 Z 后面加上“#”符号。我喜欢以 A 开头的表格。我一直在尝试找到一个函数,但没有运气。再次感谢。我很感激
    • 如果你的结构在不同的文件中也没关系。你只需要将餐厅的模型从您的 TableView didSelect 委托传递给您的 detailController。您可以在第一个索引“#”处获取完整对象并最后附加它。这样你就可以在Z的最后做#
    • 如何在第一个索引处抓取完整的对象?我尝试了几种不同的方法,但它不起作用!有什么功能可以给我看吗?对不起,我还是新手,还在学习。我试图使用: self.tableData.sort { $0.name
    • @Dian 我已经在链接中编辑了项目,还根据您的需要添加了一些关于 # 类别转移到底部逻辑的代码。请下载新的示例链接并查看。我也在答案中添加了 sn-p 。如果它对您有帮助,请接受。
    • 拉詹,感谢您的帮助。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-03
    • 1970-01-01
    • 2023-03-30
    • 2020-03-28
    • 1970-01-01
    • 2020-05-08
    相关资源
    最近更新 更多