2017-07-03 36 views
0

我對Xcode和Swift很新穎。我試圖在TableView中按字母順序顯示數據(餐廳名稱)。我有一個JSON文件,將每個餐廳分類到正確的鄰域中。代碼在視圖控制器中完美工作,我可以在部分中顯示鄰域的名稱,並在行中顯示餐廳的名稱。我的問題是,我試圖在不同的視圖控制器中的所有餐館名稱進行排序,其中各個部分顯示字母(A,B,C ...),並且我嘗試按照字母順序顯示餐館側。類似於iPhone上的聯繫人應用程序,但我需要顯示餐廳名稱的聯繫人名稱。希望我有道理。 我的代碼如下所示:在Swift的表視圖中按字母順序顯示JSON數據

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 
} 

我有所有的結構中的獨立快捷文件的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社區視圖控制器,效果很好。你可以明白這個主意! 再次提前致謝!

回答

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 
    } 
} 

餐廳類現在是分開的。還修改了鏈接中的示例並創建了一個新的DetailViewController類。

import Foundation 

class Restaurant { 
    var name = "" 

    init(name:String) { 
     self.name = name 
    } 
} 

此代碼可以改進排序邏輯。歡迎改進。

這裏是輸出 enter image description here

下面是詳細控制器 enter image description here

+0

拉詹,感謝您的幫助。我正試圖用我所擁有的實現你的代碼。我有一個DetailViewController顯示餐館的細節。這是來自我在單獨的swift文件中的結構的調用。看來代碼現在剎車,但我正在嘗試修復它。另外,有沒有辦法在Z之後加上「#」號。我喜歡用A開始。我一直在試圖找到一個函數,但沒有運氣。再次感謝。我讚賞 – Dian

+0

如果你在不同的文件中有你的結構,無所謂。喲只需將餐廳的模型從TableView didSelect委託傳遞給您的detailController。您可以在第一個索引處抓取完整的對象,該索引是'#'並最後附加它。通過這種方式,你可以使#最後的Z –

+0

你如何在第一個索引處獲取完整的對象?我嘗試了幾種不同的方法,但它不工作!有沒有可以告訴我的功能?對不起,我還在學習。我試圖使用:self.tableData.sort {$ 0.name <$ 1.name}謝謝你。 – Dian

相關問題