Swift:从 Firebase 检索数据并在表格视图中显示

Posted

技术标签:

【中文标题】Swift:从 Firebase 检索数据并在表格视图中显示【英文标题】:Swift: Retrieve data from Firebase and display in table view 【发布时间】:2018-06-27 09:15:24 【问题描述】:

我正在制作一个包含图像新闻提要的应用程序 (HomeViewController)。用户可以点击与 SiteViewController 连接的每个图像,该图像具有空数据的表格视图和一个按钮,当单击该按钮时,用户可以上传数据到 ContextSheetViewController他们在新闻提要中单击的图像。用户然后按下上传,这些数据(siteCodeTextView、areaCodeTextView、trenchTextView)被保存到 firebase 并返回到 SiteViewController。然后我想在 SiteViewController 的表视图中检索刚刚上传的图像的 siteCodeTextView 的数据值。但是,当我在 ContextSheetViewController 中按下上传时,会出现错误:Unexpectedly found nil while unwrapping an Optional value。我的 sheetId 在 SiteViewController 中打印 nil 所以我不确定如何正确检索它?有什么帮助吗?

这是我的相关视图控制器的故事板:

SiteViewController 的代码:

class SiteViewController: UIViewController 

    @IBOutlet weak var tableView: UITableView!


    var sheets = [Sheet]()
    var users = [User]()
    var sheetId: String!

    var postId: String!

    override func viewDidLoad() 
        super.viewDidLoad()

        tableView.dataSource = self
        loadSheets()

        print(postId)
        print(sheetId)
    
    func loadSheets() 
        Api.Sheet.REF_SHEETS.child(self.postId!).observe(.childAdded, with: 
            snapshot in
            Api.Sheet.observeSheets(withSheetId: snapshot.key, completion: 
                sheet in
//                self.fetchUser(uid: sheet.uid!, completed: 
                    print("sheet id: \(sheet.id)")
                    print("sheet uid: \(sheet.uid)")
                self.sheets.append(sheet)
                self.tableView.reloadData()
//                )
            )
        )
    

    func fetchUser(uid: String, completed:  @escaping () -> Void ) 

        Api.User.observeUser(withId: uid, completion: 
            user in
            self.users.append(user)
            completed()
        )
    

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
        if segue.identifier == "SheetSegue" 
            let sheetVC = segue.destination as! SheetViewController
            let sheetId = sender as! String
            sheetVC.sheetId = sheetId

        
    


extension SiteViewController: UITableViewDataSource 
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return sheets.count
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "SheetCell", for: indexPath) as! SiteTableViewCell
        let sheet = sheets[indexPath.row]

        print("sheet id: \(sheet.id)")
        print("sheet uid: \(sheet.uid)")
//        let user = users[indexPath.row]
//        cell.user = user
        cell.sheet = sheet
        cell.delegate = self
        return cell
    


extension SiteViewController: SiteTableViewCellDelegate 
    func goToSheetVC(sheetId: String) 
        performSegue(withIdentifier: "SheetSegue", sender: sheetId)

    

ContextSheetViewController 的代码:

class ContextSheetViewController: UIViewController 


    @IBOutlet weak var siteCodeTextView: UITextField!
    @IBOutlet weak var areaCodeTextView: UITextField!
    @IBOutlet weak var trenchTextView: UITextField!
    @IBOutlet weak var uploadArtefactImage: UIImageView!

    @IBOutlet weak var artefactImageView: UIImageView!

    var selectedImage: UIImage?
    var postId: String!
    override func viewDidLoad() 
        super.viewDidLoad()
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.handleSelectPhoto))
        uploadArtefactImage.addGestureRecognizer(tapGesture)
        uploadArtefactImage.isUserInteractionEnabled = true

    

    @objc func handleSelectPhoto() 
        let pickerController = UIImagePickerController()
        pickerController.delegate = self
        present(pickerController, animated: true, completion: nil)
    

    @IBAction func uploadButton_TouchUpInside(_sender: Any) 

        if let profileImg = self.artefactImageView.image, let imageData = UIImageJPEGRepresentation(profileImg, 0.1) 
            let photoIdString = NSUUID().uuidString
            print(photoIdString)
            let storageRef = Storage.storage().reference(forURL: Config.STORAGE_ROOF_REF).child("sheets").child(photoIdString)
            storageRef.putData(imageData, metadata: nil, completion:  (metadata, error) in
                if error != nil 
                    ProgressHUD.showError(error!.localizedDescription)
                    return
                
                let photoUrl = metadata?.downloadURL()?.absoluteString
                self.sendDataToDatabase(photoUrl: photoUrl!)
            )
         else 
            ProgressHUD.showError("Sheet Image can not be empty!")
        
    

    func sendDataToDatabase(photoUrl: String) 
//        let ref = Database.database().reference()
        let sheetsReference = Api.Sheet.REF_SHEETS
//        let sheetsReference = ref.child("sheets")
        let newSheetId = sheetsReference.childByAutoId().key
        let newSheetReference = sheetsReference.child(newSheetId)
        guard let currentUser = Auth.auth().currentUser else 
            return
        
        let currentUserId = currentUser.uid
        newSheetReference.setValue(["uid": currentUserId, "photoUrl": photoUrl, "siteCodeTextView": siteCodeTextView.text!, "areaCodeTextView": areaCodeTextView.text!, "trenchTextView": trenchTextView.text!], withCompletionBlock: 
            (error, ref) in
            if error != nil 
                ProgressHUD.showError(error!.localizedDescription)
                return
        
            let postSheetRef = Api.Sheet.REF_SHEETS.child(self.postId!).child(newSheetId)
//            let postSheetRef = Api.Sheet.REF_SHEETS.child("post-sheets").child(self.postId).child(newSheetId)
            postSheetRef.setValue(true, withCompletionBlock:  (error, ref) in
                if error != nil 
                    ProgressHUD.showError(error!.localizedDescription)
                    return
                
            )


            ProgressHUD.showSuccess("Success")
            self.clean()
            self.navigationController?.popViewController(animated: true)
        )
    

    func clean() 
        self.siteCodeTextView.text = ""
        self.uploadArtefactImage.image = UIImage(named: "upload")
        self.artefactImageView.image = UIImage(named: "image")
    


extension ContextSheetViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate 
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) 
        print("did Finish Picking Media")
        if let image = info["UIImagePickerControllerOriginalImage"] as? UIImage
            artefactImageView.image = image
//            selectedImage = image
//            uploadArtefactImage.image = image
        
        dismiss(animated: true, completion: nil)
    

SiteTableViewCell 代码:

protocol SiteTableViewCellDelegate 
    func goToSheetVC(sheetId: String)



class SiteTableViewCell: UITableViewCell 


    @IBOutlet weak var profileImageView: UIImageView!
    @IBOutlet weak var siteSheetLabel: UILabel!
    @IBOutlet weak var nameLabel: UILabel!

    var delegate: SiteTableViewCellDelegate?

    var sheet: Sheet? 
        didSet 
            updateView()
        
    

    var user: User? 
        didSet 
            setupUserInfo()
        
    

    func updateView() 
        siteSheetLabel.text = sheet?.siteCodeTextView

    


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

    func setupUserInfo() 
        nameLabel.text = user?.username
        if let photoUrlString = user?.profileImageUrl 
            let photoUrl = URL(string: photoUrlString)
            profileImageView.sd_setImage(with: photoUrl, placeholderImage: UIImage(named: "placeholderImg"))
        
    


    override func setSelected(_ selected: Bool, animated: Bool) 
        super.setSelected(selected, animated: animated)
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.siteSheetLabel_TouchUpInside))
        siteSheetLabel.addGestureRecognizer(tapGesture)
        siteSheetLabel.isUserInteractionEnabled = true
    

    @objc func siteSheetLabel_TouchUpInside() 

        print(sheet?.id)

        if let id = sheet?.id
            delegate?.goToSheetVC(sheetId: id)
        
    
    override func prepareForReuse() 
        super.prepareForReuse()
        profileImageView.image = UIImage(named: "placeholderImg")
    


【问题讨论】:

打印时是否看到来自 firebase 的数据? 【参考方案1】:

根据您所显示的罪魁祸首是postId,您正在使用它从 Firebase 获取数据,但您没有在任何地方显示它的值是什么。当用户点击图像时,postId 不会转移到SiteViewController

SiteViewController 中删除! 并将其替换为?,放置一个将postID 作为参数的初始化程序。

var postId:String?

func initPost(forImage postId: String) 
    self.postId=postId

在之前的新闻提要VC里面seguedidSelectForRow(我不知道你用什么来转换,初始化SiteViewController,所以当它出现时它知道要为哪个ID检索数据。

需要提及的另一件事是您正在使用observe,但您并没有移除观察者。

编辑:这个答案是基于我不知道你的 HomeVC 是什么样子的。

     if segue.identifier == "SiteSegue" 
        let siteVC = segue.destination as! SiteViewController
        let postId = sender as! String
        siteVC.postId = postId

    

【讨论】:

感谢您的帮助!我对 swift 比较陌生,所以我不确定如何放置一个将 postID 作为参数的初始化程序。我已经编辑了我的问题并添加到我以前的 VC(新闻提要)中,以在 segue 中显示我的代码,因为它正在从那里检索 post.id 好的,我编辑了我的问题,向您展示如何在您的 VC 中放置初始化程序。但是在看到您的编辑后,您可以使用另一种方法,除非您没有将新闻提要 VC 设置为 SiteViewController 的委托。 我已经编辑了我的帖子,但这里最大的问题是你为什么使用 segue 而不是 didSelectRowAt?? 我已经包含了我丢失的代码行,但是出现错误:“'SiteViewController' 类型的值没有成员'delegate',出现? 删除该行,现在它应该可以工作了,因为我已经在我的终端测试了它,但实现其他所有内容并让我知道..

以上是关于Swift:从 Firebase 检索数据并在表格视图中显示的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中从 Firebase 检索数据的问题

Swift 从 Firebase 检索数据

从 Firebase 检索和读取数据作为 NSArray (Swift 3)

从firebase实时数据库IOS Swift中检索数据

如何使用 Swift 中的 url 从 firebase 正确检索数据?

从 Firebase 检索数据等于意外 nil - swift