我是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,效果很好。你可以得到这个想法! 再次感谢!!
答案 0 :(得分:1)
我尝试使用一些不同的方法来解决您的问题。这是我制作的Sample 这是我的控制器代码,并尝试按照API提供的数据使其与联系人应用程序类似。我只是在模型中使用了餐馆名称,因为它只需要按字母顺序排序。所有其他细节和解释都在代码中的注释中提及。
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
类。
import Foundation
class Restaurant {
var name = ""
init(name:String) {
self.name = name
}
}
可以在排序逻辑中改进此代码。欢迎改进。