涉及 JSON 解析以及静态和动态 UITableView 单元格的 Swift3 项目 - 使其更加面向对象

Posted

技术标签:

【中文标题】涉及 JSON 解析以及静态和动态 UITableView 单元格的 Swift3 项目 - 使其更加面向对象【英文标题】:Swift3 project involving JSON parsing and both static and dynamic UITableView cells - making it more object-oriented 【发布时间】:2017-05-22 02:05:30 【问题描述】:

我有一个 CTA(芝加哥交通管理局)火车跟踪应用程序,它可以完全按照我的意愿执行和工作。然而,代码本身远非面向对象。

您可以选择您想要的线路,这会将您带到一个显示所有车站的车站屏幕,您可以单击它进入一个表格视图,其中显示每个车站的火车到达时间和带有数据提取的目的地火车站来自 CTA 维护的 JSON 文件。

但是,我不得不为每个火车站创建一个新的 tableView swift 文件,导致 tableView 数量巨大。如果我需要更改某些内容,我需要将该更改复制并粘贴到所有站 tableViews 中。

我认为其中一个原因是我为 Trains tableView 和 Stations tableViews 使用了静态单元格,但每个目的地车站的 tableViews 都是动态的(我这样做是因为车站永远不会改变,但目的地车站的信息会更新经常为到达的火车。此外,我不知道如何更改从车站 tableView 发送到目标车站 tableView 的 JSON 提要,以便在我尝试制作项目时每个目标车站解析不同的 JSON 文件动态 tableView 单元格)。

有没有办法让我只能为 Stations tableView 提供一个动态单元格 tableView(例如 Red Line Stations tableView 只有一个动态原型单元格)?

以下是我的项目故事板及其代码:

import UIKit

class RedHowardTableViewController: UITableViewController 

class Destinations 
    var destination: String = ""
    var time: String = ""


var feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40900&outputType=JSON"

var dataAvailable = false

var records = [Destinations]()

override func viewDidLoad() 
    super.viewDidLoad()

    parseData()


override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()

    for r in records 
        r.time = ""
        r.destination = ""
    


override func numberOfSections(in tableView: UITableView) -> Int 
    return 1


override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return dataAvailable ? records.count : 15


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    if (dataAvailable) 
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let destinationRow = records[indexPath.row]
        cell.textLabel?.text = "Heading towards " + destinationRow.destination
        cell.detailTextLabel?.text = "Arriving at: " +  destinationRow.time
        return cell
     else 
        let cell = tableView.dequeueReusableCell(withIdentifier: "PlaceholderCell", for: indexPath)
        return cell
    


func parseData() 
    guard let feedURL = URL(string: feed) else 
        return
    
    let request = URLRequest(url: feedURL)
    let task = URLSession.shared.dataTask(with: request) (data, response, error) in
        if error != nil
        
            print("Error")
        
        else 
            if let content = data 

                do 
                    let json = try JSONSerialization.jsonObject(with: content, options: []) as? [String:Any] ?? [:]
                    print(json)
                    if let ctattimetable = json["ctatt"] as? [String:Any] 
                        if let estArrivalTime = ctattimetable["eta"] as? [[String:Any]] 
                            for item in estArrivalTime

                                if let headingTowards = item["destNm"] as? String,
                                    let arrivalTime = item["arrT"] as? String 
                                    if (headingTowards != "Howard") 
                                        let record = Destinations()
                                        record.destination = headingTowards
                                        let formattedDate = String(arrivalTime.characters.suffix(8))
                                        let components = formattedDate.components(separatedBy: ":").flatMap(Int($0))
                                        let time12h = String(format: "%d:%02d", components[0] % 12, components[1]) + (components[0] < 12 ? "am" : "pm")
                                        record.time = String(time12h)
                                        self.records.append(record)
                                    
                                
                                self.dataAvailable = true
                                DispatchQueue.main.async 
                                    self.tableView.reloadData()
                                
                            
                        
                    
                
                catch  
                
            
        
    
    task.resume()


以下是我尝试主要使用动态 tableViews 执行此操作时的结果,这导致为每个 Destination tableView 解析相同的 JSON 文件:

以下所有蓝线车站的 TableViewController:

import UIKit

class BlueLineTableViewController: UITableViewController 

override func viewDidLoad() 
    super.viewDidLoad()


override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()


override func numberOfSections(in tableView: UITableView) -> Int 
    return 1


override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return bluelinestations.count


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "bluelinecell", for: indexPath)
    let station = bluelinestations[indexPath.row]
    cell.textLabel?.text = station.name
    cell.imageView?.image = UIImage(named: station.image)
    return cell


override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
    let row = indexPath.row
    if row == 0 
        BlueBelmontTableViewController().feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40890&outputType=JSON"
    
    if row == 1   
        BlueBelmontTableViewController().feed="http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40820&outputType=JSON"
       


Destination Station tableViewController 的代码显示每个站点的到达时间

import UIKit

class BlueBelmontTableViewController: UITableViewController 

class Destinations 
    var destination: String = ""
    var time: String = ""


var feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40440&outputType=JSON"
var dataAvailable = false
var records = [Destinations]()

override func viewDidLoad() 
    super.viewDidLoad()

    parseData()


override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()

    for r in records 
        r.time = ""
        r.destination = ""
    

override func numberOfSections(in tableView: UITableView) -> Int 
    return 1


override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return dataAvailable ? records.count : 15


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    if (dataAvailable) 
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) 
        let destinationRow = records[indexPath.row]
        cell.textLabel?.text = destinationRow.destination
        cell.detailTextLabel?.text = destinationRow.time
        return cell
     else 
        let cell = tableView.dequeueReusableCell(withIdentifier: "PlaceholderCell", for: indexPath)
        return cell
    


func parseData() 
    guard let feedURL = URL(string: feed) else 
        return
    
    let request = URLRequest(url: feedURL)
    let task = URLSession.shared.dataTask(with: request) (data, response, error) in
        if error != nil
        
            print("Error")
        
        else 
            if let content = data 

                do 
                    let json = try JSONSerialization.jsonObject(with: content, options: []) as? [String:Any] ?? [:]
                    print(json)

                    if let ctattimetable = json["ctatt"] as? [String:Any] 
                        if let estArrivalTime = ctattimetable["eta"] as? [[String:Any]] 
                            for item in estArrivalTime
                                if let headingTowards = item["destNm"] as? String,
                                    let arrivalTime = item["arrT"] as? String 
                                    let record = Destinations()
                                    record.destination = headingTowards
                                    record.time = arrivalTime
                                    self.records.append(record)
                                
                                self.dataAvailable = true
                                DispatchQueue.main.async 
                                    self.tableView.reloadData()
                                
                            
                        
                    
                
                catch 
                
            
        
    
    task.resume()

【问题讨论】:

【参考方案1】:

因为你使用了静态单元格,所以当你为单元格选择事件定义一个动作时,你有很多作为静态单元格的 segue,一个 segue 将对应一个 table view,因此你将有很多 table view 来控制故事板。

我认为您应该将Train Table ViewStation Table View 都更改为动态。它减少了大量的表格,易于更改和编辑。它会更灵活。

像这样:

编辑:为 segue 的目标控制器传递数据

在你的 Station View Controller 中,添加这个 segue 委托函数:

// MARK: - segue perform handle

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    super.prepare(for: segue, sender: sender)

    guard let segueIdentifier = segue.identifier else 
        return
    

    switch segueIdentifier 
    case "your_segue_identifer":
        let destinationViewController = segue.destination as? DestinationViewController
        guard let selectedRowIndex = yourTableView.indexPathForSelectedRow?.row else 
            break
        

        destinationViewController?.config(withStation station: yourStationList[selectedRowIndex])
    default:
        break
    

【讨论】:

谢谢。我会尽量让它动态工作。我编辑了上面的蓝线车站代码(参见最后一种方法),但我似乎无法将提要传递给目标视图控制器。您知道我将如何根据单击的行将 feed 变量设置为新的 url 字符串(在目标视图控制器代码中)吗? 检查我编辑的答案,我添加了代码块以将提要传递给目标视图控制器。

以上是关于涉及 JSON 解析以及静态和动态 UITableView 单元格的 Swift3 项目 - 使其更加面向对象的主要内容,如果未能解决你的问题,请参考以下文章

Java中的方法调用分析!详细解析静态分派和动态分派的执行过程

分段表转 JSON

Android Fragment 深度解析

使用动态数据进行 JSON 解析

详谈ApacheNginx和tomcat的区别以及处理静态页面和动态页面的方式

JSP静态include和动态include的区别