处理 UITableView 中的动态单元格?

Dealing with dynamic cells in a UITableView?

New Error Message

Error Message.

现在,我明白了 error message。

已更新代码,此图中显示错误消息 link error message:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = runReportTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = valuesArray[indexPath.row]
cell.SetCheckMark(cell.checkMark) //Call 'SetCheckMark' function here
cell.tapButton = {
    if cell.checkMark.isSelected == false {
        
        let data:[String:String] = [self.Facilities[indexPath.row]: "Disinfected"]
        self.InfoArray.append(data)
    }
    else {
        self.InfoArray.remove(at: indexPath.row)
    }
}

print("Responsibilities in cells: \(valuesArray)")
print("\(data)")
return cell
}

我让这段代码一直运行到“print("You taped cell #(indexPath.row)")”。此代码生成包含某些字段的此 firebase 文档:this document should have fields of the room/area text and values of "Disinfected" or "Not Disinfected" depending on whether the user selected that cell or left it unselected

因此,我现在需要此代码做的就是使用用户 select 编辑的单元格的文本 (valuesArray[indexPath.row]) 更新我的 Cloud Firestore 文档。在我的 viewController 上使用静态数量的按钮和标签之前,我已经完美地工作了,并且在我的 firebase Firestore 文档中得到了我想要的结果,如下所示:screenshot of when I had static information that I was updating in my firebase database after the user made all selections and tapped the "send report" button

但是,现在,我想知道如何在 firebase 文档中使用 selected 值“已消毒”或“未消毒”显示常量“房间 1”-“房间 21”键如果单元格是 selected/highlighted 或如果用户没有 select 单元格,我可以让我的代码自动写入该 firebase 文档“已消毒”,然后显示哪个单元格具有该值disinfected/notdisinfected 使用我从下方“Firestore 文档数据屏幕截图”中的数据中获取的单元格标签文本。

我认为这是因为我不是 100% 确定如何检查我创建的动态单元格是否 selected 或没有然后将“已消毒”或“未消毒”分配给 select在我的 Cloud Firestore 文档中编辑了单元格的文本。

如前所述,此代码打印正确的点击单元格编号和正确的点击单元格标签文本。它还成功创建了一个新的 Cloud Firestore 文档,其中没有 selected 按钮的值(“Disinfected”或“Not Disinfected”)及其匹配的单元格标签文本。

这是模拟器的屏幕截图Simulator Screenshot and a screenshot of the Cloud Firestore document data that I'm using for my cells' label text Firestore Document Data Screenshot。

import UIKit
import Firebase
import FirebaseFirestore
import SCLAlertView


class RunReportViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {


@IBOutlet weak var runReportTableView: UITableView!

    

var namesDocumentRef:DocumentReference!
var userName = ""
var userEmail = ""
var data:[String] = []
var valuesArray:[String] = []
var selectedResponsibility:[String] = []
//    var keysArray:[String] = []


override func viewDidLoad() {
    super.viewDidLoad()
    
    startObservingDB()
    
    runReportTableView.delegate = self
    runReportTableView.dataSource = self
    // Do any additional setup after loading the view.
}



// Gets user's specific room(s)/area(s)/classroom(s) responsibilities from Cloud Firestore Database to be used for checking "Disinfected" or "Not Disinfected" in order to put the text as a cell label
func startObservingDB() {
    var responsibilitiesDocumentRef:DocumentReference!
    let db = Firestore.firestore()
    let userID = Auth.auth().currentUser!.uid
    responsibilitiesDocumentRef = db.collection("UserResponsibilities").document("McGrath").collection("Custodians").document("\(userID)")
    responsibilitiesDocumentRef.addSnapshotListener { DocumentSnapshot, error in
        if error != nil{
            return
        }
        else {
            guard let snapshot = DocumentSnapshot, snapshot.exists else {return}
            guard let data = snapshot.data() else { return }
            self.valuesArray = Array(data.values) as! Array<String>
//                self.keysArray = Array(data.keys)
            
            self.runReportTableView.reloadData()
            print("Current data: \(data)")
            print("Current data has the responsibilities: \(self.valuesArray)")
            print("Current data totals \(self.valuesArray.count) items.")
        }
    }
}



@IBAction func sendReportTapped(_ sender: Any) {
    getSelectionValues()
}

func getSelectionValues() {

    let db = Firestore.firestore()
    let userID = Auth.auth().currentUser!.uid
    
    db.collection("Users").document("\(userID)").collection("UserInfo").getDocuments { (snapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
        } else {
            for document in snapshot!.documents {
                let docID = document.documentID
                self.userName = document.get("Name") as! String
                self.userEmail = document.get("Email") as! String
                
        
                print("Current document is: \(docID)")
                print("Current user's name: \(self.userName)")
            }
    

            db.collection("Run Reports").document("Custodians").collection("Custodians").document("\(String(describing: userID))").collection("Run Reports").document("\(self.getCurrentShortDate())").setData ([
            "Name": "\(String(describing: self.userName))",
            "Email": "\(String(describing: self.userEmail))",
            "Admin": Bool(false),
            "Last Updated": FieldValue.serverTimestamp(),
            ])
        }
        
        
        // getting values of selection code:
            func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
                print("The cell you tapped has the text: \(self.valuesArray[indexPath.row])")
//                    let selectedResponsibility = "\(self.valuesArray[indexPath.row])"
                
                print("You tapped cell #\(indexPath.row)")
                
                

这就是问题所在。这段代码只是我在试验,尽管我更新 firebase 文档的代码有效——“设置责任 1 的状态”有效。它只是不适用于我上面关于动态单元格的信息,这些信息都是实验性的并且是错误的,因为不起作用:

//                let currentUsersCellCount = self.valuesArray.count
                     let cell = self.runReportTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
                let dynamicCell = self.runReportTableView.cellForRow(at: indexPath)
                
                if dynamicCell?.isSelected == true {
                        let status = "Disinfected"
                    let DocumentRef = db.collection("Run Reports").document("Custodians").collection("Custodians").document("\(String(describing: userID))").collection("Run Reports").document("\(self.getCurrentShortDate())")

                        // Set the status of Responsibility 1
                        DocumentRef.updateData(["\(self.valuesArray[indexPath.row])" : "\(status)"])
        }

                    else if dynamicCell?.isSelected == false {
                        let status = "Not Disinfected"
                    let DocumentRef = db.collection("Run Reports").document("Custodians").collection("Custodians").document("\(String(describing: userID))").collection("Run Reports").document("\(self.getCurrentShortDate())")

                        // Set the status of Responsibility 1
                        DocumentRef.updateData(["\(self.valuesArray[indexPath.row])" : "\(status)"])
        }
        
 

一切正常:

    // Setup action for when "Send Report" and alert buttons are tapped
    let appearance = SCLAlertView.SCLAppearance(
                // Hide default button???
                showCloseButton: false
            )
            
    // Create alert with appearance
    let alert = SCLAlertView(appearance: appearance)
    alert.addButton("Done", action: {
        
        // Show SendReportViewController after successfully sent report and alert button is tapped
                        let storyboard = UIStoryboard(name: "Main", bundle: nil)
                        let vc = storyboard.instantiateViewController(withIdentifier: "SendReportViewController")
                        vc.modalPresentationStyle = .overFullScreen
                        self.present(vc, animated: true)
                         // create button on alert
                        print("'Done' button was tapped.")
    })
            
    alert.showSuccess("Report Sent!", subTitle: "Your Run Report has been sent to your supervisor.", closeButtonTitle: "Done", timeout: nil, colorStyle: SCLAlertViewStyle.success.defaultColorInt, colorTextButton: 0xFFFFFF, circleIconImage: nil, animationStyle: .topToBottom)
    
    }
}
        
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    print("The cell you tapped has the text: \(valuesArray[indexPath.row])")
//    let selectedResponsibility = "\(valuesArray[indexPath.row])"


print("You tapped cell #\(indexPath.row)")
}


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return valuesArray.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = runReportTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = valuesArray[indexPath.row]


print("Responsibilities in cells: \(valuesArray)")
print("\(data)")

return cell
}

   // using date to create new firestore document with date as the title
func getCurrentShortDate() -> String {
    let todaysDate = NSDate()
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "(MM-dd-yy)"
    let DateInFormat = dateFormatter.string(from: todaysDate as Date)
    return DateInFormat
}

}

如果您想将有关您在 fireStore 文档中选择的单元格的信息存储为 Text of the cellDisinfectedNot Disinfected,即 ConferenceRoomDisinfected,那么这就是我的建议。

首先,在tableViewCell文件中,添加以下属性

var tapButton: (() -> Void)? = nil //This will allow you to get the text of the row you have selected

然后,我想你的单元格内有一个按钮,在你的情况下它位于左侧,可以点击或取消点击。让我们将该按钮名称称为 checkMark,这样它就会像这样在您的 tableviewCell 文件中声明。

@IBOutlet weak var checkMark: UIButton!

现在,添加一个函数 SetCheckMark 以便用户可以查看单元格是否已选中。此外,您将需要两个图像,它们将被分配给处于选中或未选中状态的按钮。

@IBAction func SetCheckMark(_ sender: UIButton) {
    //If button is selected, then
    if checkMark.isSelected == true {
               checkMark.setImage(UIImage(named: "Check"), for: .normal)
               checkMark.isSelected = false


           }
           else {
               checkMark.setImage(UIImage(named: "UnCheck"), for: .normal)
                checkMark.isSelected = true

           }
   
    tapButton?() //This is the property that we declared above.
}

现在,你差不多完成了。进入你的主文件。首先在File开头添加一个字典来保存信息。

var InfoArray:[[String:String]] = [["":""]]

现在,在您的 tableView cellForRowAt indexPath: IndexPath 函数中,添加这些行。

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
 let cell = runReportTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

    cell.label.text = valuesArray[indexPath.row]
    cell.SetCheckMark(cell.checkMark) //Call `SetCheckmark` function here
    cell.tapButton = {
        if cell.checkMark.isSelected == false {
            
            let data:[String:String] = [self.Facilities[indexPath.row]: "Disinfected"]
            self.InfoArray.append(data)
        }
        else {
            self.InfoArray.remove(at: indexPath.row)
        }
           }
    
    
    return cell
}

用户选择完选项后,它将点击 sendReport 按钮。然后,在该按钮内,您可以像这样 post 将数据保存到 firestore 文档。

db.collection("CollectionName").document("DocumentName").setData(["Facilities" : self.InfoArray])

您的 tableViewCell 文件应如下所示。

class YourTableViewCell: UITableViewCell {

@IBOutlet weak var checkMark: UIButton!

var tapButton: (() -> Void)? = nil


@IBAction func SetCheckMark(_ sender: UIButton) {
    if checkMark.isSelected == true {
               checkMark.setImage(UIImage(named: "Checkbox"), for: .normal)
               checkMark.isSelected = false
           }
           else {
               checkMark.setImage(UIImage(named: "UnCheckbox"), for: .normal)
                checkMark.isSelected = true

                }
    
       tapButton?()
    }
 }

应该可以。如果您有任何问题,请立即告诉我。