在Swift的表格视图中按字母顺序显示JSON中的数据 [英] Display data from JSON in alphabetical sections in Table View in Swift
问题描述
我对Xcode和Swift还是很陌生.我试图在TableView中按字母顺序显示数据(餐厅名称).我有一个JSON文件,将每个餐厅分类为正确的邻域.该代码在视图控制器中运行良好,在该控制器中,我在各节中显示邻域的名称,并在行中显示餐厅的名称.我的问题是我正在尝试在不同的视图控制器中对所有餐厅名称进行排序,其中各节显示字母(A,B,C ...),并且我试图在每个节下按字母顺序显示餐厅并在其上显示索引边.类似于iPhone上的联系人应用程序",但联系人姓名保持不变,我需要显示餐厅名称.希望我有道理. 我的代码如下:
I am pretty new to Xcode and Swift. I am trying to display data (restaurants names) in alphabetical order in TableView. I have a JSON file that sorts each restaurant into the correct neighborhood.The code works perfectly in the view controller where I m displaying the name of the neighborhood in sections and the name of the restaurant in rows. My problem is that I am trying to sort all the restaurants names in a different view controller where the sections display the Alphabet (A,B,C...) and under each sections I am trying to display the restaurants alphabetically with index on the side. Something similar to the Contact App on the iPhone but instate of contact names I need to show the restaurant names. Hope I make sense. My code looks like this:
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的所有结构
I have a separate swift file with all the structure for the 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
这是邻居视图控制器的效果很好的图像.你可以明白的! 再次感谢!
This is a image of the neighborhoods view controller that works great. You can get the idea! Thanks again in advance!!
推荐答案
我尝试使用一些不同的方法来解决您的问题.这是我制作的示例.
这是我的控制器代码,并尝试根据API提供的数据使其类似于contact app.我只是在模型中使用了餐厅名称,因为只需要按字母顺序排序.代码中的注释中提到了所有其他详细信息和解释.
I tried to solve your problem using some different approach. Here is the Sample I made.
Here is my controller code and tried to make it as similar to contact app as per the data provided by the API. I just took restaurant name in model as It will only be needed for sorting in alphabetical order. All the other details and explanation are mentioned in comments within the code.
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
}
}
现在餐厅类被分离了.还修改了链接中的Sample并创建了一个新的DetailViewController
类.
The Restaurant class is now separated. Also modified the Sample in the link and created a new DetailViewController
class.
import Foundation
class Restaurant {
var name = ""
init(name:String) {
self.name = name
}
}
可以在排序逻辑中改进此代码.欢迎改进.
This code can be improved in the sort logic. Improvements are welcome.
以下是输出:
这是详细信息控制器:
这篇关于在Swift的表格视图中按字母顺序显示JSON中的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!