【问题标题】:Swift display firebase data on tableview not shownSwift在tableview上显示firebase数据未显示
【发布时间】:2020-06-19 20:15:35
【问题描述】:

我正在制作使用 firebase 作为数据库的应用程序,但我似乎无法将我的数据显示到我的 tableview 中。我检查了我的 Firebase,我的所有数据都很好,即使我添加了新数据,数据也会立即显示在我的 Firebase 中。但似乎我在这里有一些遗漏的逻辑......有人可以帮助我吗?

*编辑代码不起作用的 1 行

这是我的主控制器:

class MainController: UITableViewController, AddPatientControllerr {


private var patientLists = [PatientList]() 
var Segue : String = "PatientName"
var Segue2 : String = "PatientNotes"
let user : User = Auth.auth().currentUser! 

private var rootRef : DatabaseReference!// 1. buat nyambung ke root db

override func viewDidLoad() {
    super.viewDidLoad()
   
    self.rootRef = Database.database().reference() 
    
    populateList()
    
    tableView.delegate = self
    tableView.dataSource = self

}

// MARK : Firebase Function

private func populateList() {
    
    self.rootRef.child(self.user.emailWithoutSpecialChar).observe(.value) { (snapshot) in 
        
        self.patientLists.removeAll()
        
        let pasienListDict = snapshot.value as? [String:Any]  ?? [:] 
        
        for (key,_) in pasienListDict {
            
            if let pasienlistdict = pasienListDict[key] as? [String:Any]{

                if let pasienlist = PatientList(pasienlistdict) { // this line of code is not working 
                    self.patientLists.append(pasienlist)
                   
                }else {
                   print("your condition not working")
                }
            }
            
        }
            DispatchQueue.main.async {
           self.tableView.reloadData()
       }
        
        
    }
    
}

// MARK : Func delegate

func addPatientData(controller: UIViewController, nama: String, tglLahir: String, Telp: String, berat: String, Tinggi: String, golDarah: String) {
       
    let patientList = PatientList(name: nama, tglLahir: tglLahir, Telp: Telp, berat: berat, Tinggi: Tinggi, golDarah: golDarah)
       self.patientLists.append(patientList)
              
       let userRef = self.rootRef.child(self.user.emailWithoutSpecialChar)
       let patientListRef = userRef.child(patientList.name)
       patientListRef.setValue(patientList.toDictionary())
      
       controller.dismiss(animated: true, completion: nil)

       DispatchQueue.main.async {
           self.tableView.reloadData()
       }
   }

// MARK : Segue
   
   override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
       
       if segue.identifier == Segue {
           let nc = segue.destination as! UINavigationController
           let addPatientName = nc.viewControllers.first as! ProfileController
           addPatientName.delegate = self
           
           }
           
           else if segue.identifier == Segue2 {
           
           guard let indexPath = self.tableView.indexPathForSelectedRow else {return}
            
           let nc = segue.destination as! PasienProfileController
           nc.pasien = self.patientLists[indexPath.row]
     
       }
   
   }
 

//MARK : TableView

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        let pasienList = self.patientLists[indexPath.row]
        let pasienListRef = self.rootRef.child(pasienList.name)
        pasienListRef.removeValue()
    }
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
    return self.patientLists.count
}


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? MainCell else {return UITableViewCell()}
    let patientListt = self.patientLists[indexPath.row]
    
    cell.NameLbl.text = patientListt.name

    return cell
  }  
}

这是我保存数据和字典的模型:

import Foundation

typealias JSONDictionary  = [String:Any]

class PatientList { 

var name : String!
var tglLahir : String!
var Telp : String!
var berat : String!
var Tinggi : String!
var golDarah : String!
var patientNote :[PatientNote] = [PatientNote]() //ini buat nyimpen notes2 dari tiap2 pasien 

init(name : String, tglLahir : String, Telp : String, berat : String, Tinggi : String, golDarah : String) {
    self.name = name
    self.tglLahir = tglLahir
    self.berat = berat
    self.Tinggi = Tinggi
    self.golDarah = golDarah
    self.Telp = Telp
}

init?(_ dictionary :[String:Any]){
    
    guard let name = dictionary["Name"] as? String else {
        return nil
    }
    guard let berat = dictionary["BeratBadan"] as? String else {
        return nil
    }
    guard let tglLahir = dictionary["TanggalLahir"] as? String else {
        return nil
    }
    guard let Tinggi = dictionary["TinggiBadan"] as? String else {
        return nil
    }
    guard let golDarah = dictionary["GolonganDarah"] as? String else {
        return nil
    }
    guard let Telp = dictionary["Telefon"] as? String else {
        return nil
    }
    self.name = name
    self.berat = berat
    self.tglLahir = tglLahir
    self.Tinggi = Tinggi
    self.golDarah = golDarah
    self.Telp = Telp
    let pasienListDictionary = dictionary["patientNote"] as? [JSONDictionary]
    
    if let dictionaries = pasienListDictionary {
        self.patientNote = dictionaries.compactMap(PatientNote.init)
    }
}

func toDictionary() -> [String:Any] { // ini buat dictionary buat convery object jd string:any, jd biar ga ngubah satu2 kl ada yg salah gituu
    
    return ["Name":self.name, "BeratBadan":self.berat, "TanggalLahir":self.tglLahir, "TinggiBadan":self.Tinggi, "golDarah":self.golDarah, "Telefon":self.Telp, "patientNote":self.patientNote.map{ patientNote in
        return patientNote.toDictionary()
    }]
}

}

这是我的火力基地:

[![Firebase][1]][1]

对于初学者,我只需要在我的表格视图中显示我的名字,在这种情况下我什至无法在我的表格视图中显示名称数据

我似乎无法找出为什么数据不会显示在我的 tableview 中....xcode 没有显示错误

有人可以帮助我吗?谢谢

firebase json

"afipermanalivecom" : {
    "Apiyyy" : {
        "BeratBadan" : "",
        "Name" : "Apiyyy",
        "TanggalLahir" : "20-05-2020",
        "Telefon" : "",
        "TinggiBadan" : "",
        "golDarah" : "A+"
    },
    "CocaCola" : {
        "BeratBadan" : "80",
        "Name" : "CocaCola",
        "TanggalLahir" : "20-06-2020",
        "Telefon" : "0878099996049",
        "TinggiBadan" : "190",
        "golDarah" : "A-"
    },
    "Jamsey" : {
        "BeratBadan" : "",
        "Name" : "Jamsey",
        "TanggalLahir" : "19-06-2020",
        "Telefon" : "",
        "TinggiBadan" : "",
        "golDarah" : "A-"
    }
},

"puffygmailcom" : {
    "Batman" : {
        "Name" : "Batman"
    },
    "Stitchh" : {
        "Name" : "Stitchh"
    }
}

【问题讨论】:

  • 一些事情。最重要的是,请不要使用电子邮件地址作为密钥。不更改电子邮件地址的原因有很多,如果发生这种情况,您必须扫描、删除并重新写入整个数据库中对它的每个引用。使用 userId 来引用用户,并将该引用存储为子节点。请在问题中将结构作为 test 包括在内,这样如果我们想在答案中使用它,我们就不必重新输入所有内容。要获取您的 Firebase 结构,请使用 Firebase 控制台->导出 JSON,然后复制并粘贴您的结构的 sn-p。
  • 这个self.rootRef.child(self.user.emailWithoutSpecialChar).observe(.value) 将同时加载节点“CocaCola”和“Jamsey”等(在一个大快照中)。目标是获取每个节点内的子数据,例如BeratBadan,名称等?尽管如此,对真实世界名称的硬编码键通常是一个坏主意,这些键应该使用 .childByAutoId 创建,因为无论如何产品名称都存储在节点中。请用更多的细节和清晰度更新您的问题,并删除图像并包含基于文本的 Firebase 结构。
  • 还有一件事。 Firebase 闭包中不需要 dispatchQueues DispatchQueue.main.async。 UI 调用总是在主线程上调用,而网络调用在后台线程上。这样就可以去掉了。 :-)
  • aaa 好的,谢谢@jay,我将尝试实施您的建议,因为我刚刚开始学习 firebase,我将使用 firebase 中的 JSON 更新我的问题

标签: ios swift firebase tableview


【解决方案1】:

从问题中的代码和结构看来,有一个医生和患者列表,其中患者是医生的子节点。我将发布一个解决方案,然后发布一些有关更改的重要建议。

这是现有的 Firebase 结构。请注意,我们没有使用电子邮件地址作为节点键 - 这是很多额外的工作,如果电子邮件地址发生变化,整个数据库将被扫描,节点被读取、删除和重写。应该使用 .childByAutoId 生成动态节点键(可能会更改的键,例如电子邮件) - 为了便于阅读,我使用了医生_0、医生_1 等。

{
  "doctor_0" : {
    "name" : "Dr. Doolittle",
    "patient_list" : {
      "patient_0" : {
        "blood_type" : "O-",
        "name" : "Henry"
      },
      "patient_1" : {
        "blood_type" : "AB-",
        "name" : "Leroy"
      }
    }
  },
  "doctor_1" : {
    "name" : "Dr. McCoy",
    "patient_list" : {
      "patient_2" : {
        "blood_type" : "O+",
        "name" : "Steve"
      }
    }
  }
}

我有两个类来保存这些数据,一个 DoctorClass 和 PatientClass,其中 Patient 类是 DoctorClass 中的一个数组。请注意,医生可能没有任何患者,因此我将其视为可选。

class DoctorClass {
    var doc_id = ""
    var doc_name = ""
    var patients = [PatientClass]()
    
    convenience init(withId: String, andName: String, maybePatientList: DataSnapshot?) {
        self.init()
        self.doc_id = withId
        self.doc_name = andName
        
        if let patientList = maybePatientList {
            let allPatientsSnap = patientList.children.allObjects as! [DataSnapshot]
            for patientSnap in allPatientsSnap {
                let patient = PatientClass(patientSnap: patientSnap)
                self.patients.append(patient)
            }
        }
    }
}

class PatientClass {
    var patient_id = ""
    var patient_name = ""
    var blood_type = ""
    
    convenience init(patientSnap: DataSnapshot) {
        self.init()
        self.patient_id = patientSnap.key
        self.patient_name = patientSnap.childSnapshot(forPath: "name").value as? String ?? "No Name"
        self.blood_type = patientSnap.childSnapshot(forPath: "blood_type").value as? String ?? "No blood type"
    }
}

最后是读取所有医生并用他们的病人填充他们的病人数组的代码。

var docAndPatientList = [DoctorClass]()

func loadDoctorsAndPatients() {
    let doctorsRef = self.ref.child("doctors") //self.ref points to *my* firebase
    
    doctorsRef.observeSingleEvent(of: .value, with: { snapshot in
        let allDoctorsSnapshot = snapshot.children.allObjects as! [DataSnapshot]
        for docSnap in allDoctorsSnapshot {
            let docId = docSnap.key
            let docName = docSnap.childSnapshot(forPath: "name").value as? String ?? ""
            let patientSnap = docSnap.childSnapshot(forPath: "patient_list")
            let doc = DoctorClass(withId: docId, andName: docName, maybePatientList: patientSnap)
            self.docAndPatientList.append(doc)
        }
    })
}

然后让我们打印出来

func printDoctorsAndPatients() {
    self.docAndPatientList.forEach { doctor in
        print("Dr: \(doctor.doc_name)")
        for patient in doctor.patients {
            print("  patient: \(patient.patient_name)  bloodtype: \(patient.blood_type)")
        }
    }
}

和输出

Dr: Dr. Doolittle
  patient: Henry  bloodtype: O-
  patient: Leroy  bloodtype: AB-
Dr: Dr. McCoy
  patient: Steve  bloodtype: O+

这将适用于现有结构,但如果,例如,一个病人有两个医生怎么办?或者,如果我们想查询 Firebase 中所有 O- 型血的患者怎么办?它不会(轻松地)使用这种结构。

这是一个更好的计划

root_ref
   doctors
      doctor_0
         name : "Dr. Doolittle"
         patients
            patient_0 : true
            patient_1 : true
      doctor_1
         name : "Dr. McCoy"
         patients
            patient_2 : true

和患者

root_ref
   patients
      patient_0
         blood_type : "O-"
         doctors:
            doctor_0: true
         name : "Henry"
      patient_1
         blood_type : "AB-"
         doctors:
            doctor_0: true
         name : "Leroy"
      patient_2
         blood_type : "O+"
         doctors:
            doctor_1: true
         name : "Steve"

这种结构提供了更多的查询灵活性和可扩展性。

【讨论】:

  • 感谢您提供详细的答案和代码,我非常感谢它,也感谢您提供的 json ......所以我应该重构我所有的 firebase 代码并改为使用您的参考,我会先尝试一下,但感谢朋友的提示
【解决方案2】:

只是一些提示,也许是一个解决方案, 我建议使用firebase Cloud而不是firebase实时firebase,它更快更可靠,特别是如果您尝试从数组或字典中查询数据,我可以看到您正在尝试从字典中检索数据,这是您要注意的一件事Firebase 是否将您的 swift 词典存储为客观 C 词典,所以这是您要注意的一件事!尝试检查您是否使用了正确的重用标识符。

如果您仍然无法获得它,请告诉我!

【讨论】:

  • 感谢先生的建议,尽管我仍然不知道如何实现它,因为我从 udemy 教程中学习了这个 firebase 应用程序,我只是稍微更改了数据。从教程中,他刚刚添加了一个数据,即“姓名”,它可以工作,所以我想我想添加另一个数据,如“生日等”。但现在数据没有显示
  • @afipermana 虽然回答很受赞赏,但答案指出 Firestore“更快”且“更可靠”并且不准确。在许多情况下,RTDB 将 Firestore 用于检索数据并具有同等的可靠性。此外,firebase 将您的 swift 字典存储为目标 C 字典 并不准确,因为 RTDB 不是 Objc,它是 JSON 数据,因此它根本不存储对象。该数据可以加载到代码中的各种对象中。澄清一下,NSDictionary 在 CODE 中,而 RTDB 中存储的是 json。
【解决方案3】:

如果您想返回数据列表,则必须使用.childAdded 而不是.value

所以,你的代码应该是这样的:

self.rootRef.child(self.user.emailWithoutSpecialChar).observe(.childAdded) { (snapshot) in

       // do your stuff here
}

*salam sesama orang 印度尼西亚 :)

【讨论】:

  • aa halo mas makasih udh 响应,tp masih blm bisa nih mas codenya datanya ga muncul juga di tableview ..... *indo 骄傲 :)
  • '.value' 返回数据列表。有关示例,请参阅入门指南 Working with Lists of Data。在这种情况下, .childAdded 遍历每个子节点,一次返回一个,并为添加的新子节点留下一个观察者。而.value 一次返回列表中的所有节点,并为任何新的更改留一个观察者。所以行为不同但最终数据相同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-17
  • 1970-01-01
相关资源
最近更新 更多