如何在 Swift 4 中将条件实现到 UITableViewDataSource

How to implement a conditional into an UITableViewDataSource in Swift 4

我正在使用 Swift 4 创建一个 iOS 应用程序,然后尝试使用 Alamofire 从外部 API 获取数据,然后将此数据转换为 JSON 与 Swifty JSON 并在 UIViewTable 中呈现给用户。我想根据 API 发送的数据类型添加条件(如 if 或 swift 语句)以使用不同类型的数据结构。

我有多个 swift 文件,一个用于 API 请求,另一个用于函数,一个用于 UITableCell 结构声明。

我想在 NotificationsViewController 中添加一个 if o switch 语句,这样可以获得一种 API 响应。在 createCells 函数中,我得到了通知的类型,因此我可以将必要的数据设置到响应中。此代码已获取数据并将其放入具有自定义类型 NotificationData 的二维数组中。问题是当我想根据二维数组中的通知类型添加不同类型的自定义单元格时。

* 通知ViewController * 项目主界面文件


class NotificationsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    private let request = GetNotificationsRequest()
    private let functions = Functions()

    (...)

    var cells: [[NotificationData]] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let urlToExecute = URL(string: functions.generateUrl(stage: "dev", parameters: "appnotification/notificatios/\(idAssociation!)/\(idUser!)/10/1", side: "inside")) else {
            return
        }
        request.execute(urlToExecute, user: userName as! String, pass: userPassword as! String) { (json, noItems, statusCode, error) in
            print(urlToExecute)
            if let error = error {
                print("Ha ocurrido un error.\n\(error)")
            }
            else {
                //--------------------------- Se ha realizado el llamado
                self.cells = self.functions.createCells(json: json!, noItems: noItems!)
                print(type(of: self.cells))
                // Output: Array<Array<NotificationData>>
                print(self.cells.count)
                // Output: 10
            }
        }        
    }

    //I WANT TO ADD THE IF OR SWITCH STATEMENT HERE BUT XCODE GETS AN ERROR


    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("Hay \(cells.count) celdas.")
        return cells.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        //for index in 0..<cells.count {
            //switch cells[index][indexPath.row].typeLabel {
            //case "Score":
        let cell = tableView.dequeueReusableCell(withIdentifier: "ScoreCell") as! ScoreCell
        cell.fullNameLabel.text = cells[indexPath.row][indexPath.row].fullNameLabel
        cell.agoLabel.text = cells[indexPath.row][indexPath.row].agoLabel
        cell.sisLabel.text = cells[indexPath.row][indexPath.row].sisLabel
        cell.rcLabel.text = cells[indexPath.row][indexPath.row].rcLabel
        cell.soLabel.text = cells[indexPath.row][indexPath.row].soLabel
        cell.oLabel.text = cells[indexPath.row][indexPath.row].oLabel
        cell.diaLabel.text = cells[indexPath.row][indexPath.row].diaLabel
        cell.tempLabel.text = cells[indexPath.row][indexPath.row].tempLabel
        cell.respLabel.text = cells[indexPath.row][indexPath.row].respLabel
        cell.avpuLabel.text = cells[indexPath.row][indexPath.row].avpuLabel
        cell.scoreLabel.text = cells[indexPath.row][indexPath.row].scoreLabel
        print(cell)
        return cell
        //}
    }
}

* GetNotifications() 函数 * 该函数然后使用 Alamofire

从 API 获取数据
    let functions = Functions()
    typealias WebServiceResponse = (JSON?, Int?, Int?, Error?) -> Void
    //Definición del método llamado execute() que realiza la sequest
    func execute(_ url:URL,user: String, pass: String, completion: @escaping WebServiceResponse) {
        //Definición de headers y credenciales para realizar la request
        let usr = "\(user)"
        //let usr = "USER"
        let pass = "\(pass)"
        //let pass = "PASSWORD"
        let parameters: Parameters = [:]
        let credentialsData = "\(usr):\(pass)".data(using: String.Encoding.utf8)!
        let codCredentials = credentialsData.base64EncodedString(options: [])
        let headers = [
            "Authorization": "Basic \(codCredentials)"
        ]

        //Definición del tipo de request, envío de headers para la autenticación y establecimiento de reglas de validación
        Alamofire.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers) .validate(statusCode: 200..<300) .responseJSON { response in
            let statusCode = response.response?.statusCode
            print(headers)
            print(usr)
            print(pass)
            switch response.result {
            case .success(let value):
                let json = JSON(value)
                let noItems = json["notifications"].count
                completion(json, noItems, statusCode, nil)
                print("Se ejecutó el llamado correctamente. Contiene \(noItems) ítems.")
            case .failure(let error):
                completion(nil, nil, statusCode, error)
                print("Ha ocurrido un error al ejecutar el llamado")
                print(error)
            }
        }
    }
}

* createCells() 函数 * 函数然后获取 API 数据 json(在 Swifty JSON 中)并使用 NotificationData 结构转换为二维数组并将其保存在 arrayNotifications

func createCells(json: JSON, noItems: Int) -> Array<Array<NotificationData>> {

        var arrayNotifications = [[NotificationData]]()
        for index in 0..<noItems {
            var type = json["notifications"][index]["idnotification_type"].rawString()!
            var notification = [NotificationData]()

            switch type {
            case "1":
                print("Ingreso")
                type = "Ingreso"
                var ago = ""
                let agoWithoutFormat = json["notifications"][index]["detail"]["start"].rawString()!
                print(agoWithoutFormat)
                var fullName = json["notifications"][index]["detail"]["name"].rawString()!; fullName += " "; fullName += json["notifications"][index]["detail"]["lastname"].rawString()!
                let reason = json["notifications"][index]["detail"]["reason_for_admission"].rawString()!
                let room = json["notifications"][index]["detail"]["room"].rawString()!
                let floor = json["notifications"][index]["detail"]["floor"].rawString()!
                let timeStart = json["notifications"][index]["detail"]["start"].rawString()!

                let dateFormatterGet = DateFormatter()
                dateFormatterGet.dateFormat = "yyyy-MM-dd HH:mm:ssZZZZZ"
                //according to date format your date string
                if let date = dateFormatterGet.date(from: agoWithoutFormat) {
                    ago = date.self.timeAgoDisplay()
                    print(ago)
                } else {
                    print("Se ha producido un error al codificar la hora")
                    ago = "Hace tiempo."
                }
                // --------- AGREGAR notificación al array
                notification = [NotificationData(typeLabel: type, agoLabel: ago, fullNameLabel: fullName, sisLabel: "", diaLabel: "", rcLabel: "", tempLabel: "", soLabel: "", respLabel: "", oLabel: "", avpuLabel: "", scoreLabel: "", reasonLabel: reason, roomLabel: room, floorLabel: floor, timeStartLabel: timeStart, dateStartLabel: "", timeEndLabel: "", dateEndLabel: "")]
                arrayNotifications.append(notification)
            case "2":
                print("Egreso")

            case "3":
                print("Score")
                type = "Score"
                var ago = ""
                let agoWithoutFormat = json["notifications"][index]["detail"]["time"].rawString()!
                //print(agoWithoutFormat)
                var fullName = json["notifications"][index]["detail"]["name"].rawString()!; fullName += " "; fullName += json["notifications"][index]["detail"]["lastname"].rawString()!
                let sis = json["notifications"][index]["detail"]["detail"]["sistolica"].rawString()!
                let dia = json["notifications"][index]["detail"]["detail"]["diastolica"].rawString()!
                let rc = json["notifications"][index]["detail"]["detail"]["ritmocardiaco"].rawString()!
                let temp = json["notifications"][index]["detail"]["detail"]["temperatura"].rawString()!
                let so = json["notifications"][index]["detail"]["detail"]["saturaciondeoxigeno"].rawString()!
                let resp = json["notifications"][index]["detail"]["detail"]["respiracionesxminuto"].rawString()!
                let o = json["notifications"][index]["detail"]["detail"]["oxigenosuplementario"].rawString()!
                let avpu = json["notifications"][index]["detail"]["detail"]["avpu"].rawString()!
                let score = json["notifications"][index]["detail"]["total"].rawString()!
                //let score = json["notifications"][index]["detail"]["detail"]["avpu"].rawString()!
                let dateFormatterGet = DateFormatter()
                dateFormatterGet.dateFormat = "yyyy-MM-dd HH:mm:ss"
                //according to date format your date string
                if let date = dateFormatterGet.date(from: agoWithoutFormat) {
                    ago = date.self.timeAgoDisplay()
                    print(ago)
                } else {
                    print("Se ha producido un error al codificar la hora")
                    ago = "Hace tiempo."
                }
                notification = [NotificationData(typeLabel: type, agoLabel: ago, fullNameLabel: fullName, sisLabel: sis, diaLabel: dia, rcLabel: rc, tempLabel: temp, soLabel: so, respLabel: resp, oLabel: o, avpuLabel: avpu, scoreLabel: score, reasonLabel: "", roomLabel: "", floorLabel: "", timeStartLabel: "", dateStartLabel: "", timeEndLabel: "", dateEndLabel: "")]
                arrayNotifications.append(notification)
                //print(notification)
            case "4":
                print("Recordatorio de Score")

            case "5":
                print("Deterioro fisiológico")

            default:
                print("Ha ocurrido un error al crear la celda.")

            }
        }
        //print(arrayNotifications)
        return arrayNotifications
    }
}

* 通知数据 * NotificationData 的结构

struct NotificationData {
    var typeLabel: String
    var agoLabel: String
    var fullNameLabel: String
    var sisLabel: String
    var diaLabel: String
    var rcLabel: String
    var tempLabel: String
    var soLabel: String
    var respLabel: String
    var oLabel: String
    var avpuLabel: String
    var scoreLabel: String
    var reasonLabel: String
    var roomLabel: String
    var floorLabel: String
    var timeStartLabel: String
    var dateStartLabel: String
    var timeEndLabel: String
    var dateEndLabel: String
}

* 积分单元 * 一个自定义的 UITableViewCell 定义了一个 Score 原型单元格

class ScoreCell: UITableViewCell {
    @IBOutlet weak var typeLabel: UILabel!
    @IBOutlet weak var agoLabel: UILabel!
    @IBOutlet weak var fullNameLabel: UILabel!
    @IBOutlet weak var sisLabel: UILabel!
    @IBOutlet weak var diaLabel: UILabel!
    @IBOutlet weak var rcLabel: UILabel!
    @IBOutlet weak var tempLabel: UILabel!
    @IBOutlet weak var soLabel: UILabel!
    @IBOutlet weak var respLabel: UILabel!
    @IBOutlet weak var oLabel: UILabel!
    @IBOutlet weak var avpuLabel: UILabel!
    @IBOutlet weak var scoreLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

* IngressCell * 一个自定义的 UITableViewCell 定义了一个 Ingress 原型单元

class IngressCell: UITableViewCell {
    @IBOutlet weak var reasonLabel: UILabel!
    @IBOutlet weak var agoLabel: UILabel!
    @IBOutlet weak var patientNameLabel: UILabel!
    @IBOutlet weak var descriptionLabel: UITextView!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
}

我试图在 NotificationsViewController 中添加一个 if 或 switch 语句来获取通知的类型,例如如果类型为 3,则类型为 Score,因此我必须使用名为 ScoreCell 的原型单元格 let cell = tableView.dequeueReusableCell(withIdentifier: "ScoreCell") as! ScoreCell,但如果类型为 1,则类型为 Ingress,因此必须更改为 let cell = tableView.dequeueReusableCell(withIdentifier: "IngressCell") as! IngressCell 并使用 Ingress 原型单元格。 当我尝试在 ViewController 中添加这些条件时,xcode 标记错误。在 NotificationsViewController 中包含尝试过的代码作为注释。你能帮帮我吗?

你需要关心cellForRowAt

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

    let typeSection = array[indexPath.row].type

    switch typeSection {
    case .CenterTitleCell:
        return getCenterTitleCell(tableView, indexPath)
    case .CenterDescriptionCell:
        return getCenterDescriptionCell(tableView, indexPath)
    case .CenterImageCell:
        return getImageCell(tableView, indexPath)
    case .FooterTitleCell:
        return getFooterViewCell(tableView, indexPath)
    }
}

其中类型是 enum 可能的对象类型

使用具有一项要求的协议

protocol NotificationData {
    var type : String { get }
}

然后使用不同的结构,例如仅声明属于该结构的成员

struct Ingreso : NotificationData {
   let type : String

   let room : String
   let floor : String

   // other members 
}

struct Egreso : NotificationData {
   let type : String

   // other members
}

struct Score : NotificationData {
   let type : String

   let sis: String
   let dia: String
   // other members
}

createCells 中根据类型创建不同的结构并分配 type.

不清楚你是否真的需要一个二维数组,简单的解决方案是声明一个一维数组作为协议类型,并按type

对数组进行排序
var cells = [NotificationData]()

cellForRow 中打开 type,获取项目并将其转换为实际静态类型以访问结构成员

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

    let item = cells[indexPath.row]
    switch item.type {
       case "Score":
           let cell = tableView.dequeueReusableCell(withIdentifier: "ScoreCell", for: indexPath) as! ScoreCell
           let score = item as! Score

           // assign values to the UI
           return cell

        case "Ingreso":
           let cell = tableView.dequeueReusableCell(withIdentifier: "IngresoCell", for: indexPath) as! IngresoCell
           let ingreso = item as! Ingreso

           // assign values to the UI
           return cell

        case "Egreso":
           let cell = tableView.dequeueReusableCell(withIdentifier: "EgresoCell", for: indexPath) as! EgresoCell
           let egreso = item as! Egreso

           // assign values to the UI
           return cell

        // and so on