You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase实时数据库获取userImage字符串传递问题求助

Firebase实时数据库异步获取userImage无法return的问题解决

在从Firebase实时数据库请求获取字符串userImage时,无法直接用return返回该值,系统提示错误:Unexpected non-void return value in void function,需要将userImage作为参数传入importComment对象中,相关代码如下:

func datenBankAbfrage() {
    print("datenbankabfrage getriggert")
    dic = [:]
    for name in myFeed.myArray1[0..<myFeed.myArray1.count] {
        ref = Database.database().reference().child("placeID/\(name)")
        
        ref.observe(.value) { (snapshot) in
            self.dic[name] = []
            
            var specificNameVideos = [importComment]()
            
            for video in snapshot.children.allObjects as! [DataSnapshot] {
                let Object1 = video.value as? [String: AnyObject]
                 let timestampDate = NSDate(timeIntervalSince1970: Double(Object1?["userTime"] as! NSNumber)/1000)
                let dateFormatter = DateFormatter()
                dateFormatter.timeZone = NSTimeZone.local
                dateFormatter.dateFormat = "dd.MM.YY hh:mm"
                let time = dateFormatter.string(from: timestampDate as Date)
                print(time + "Uhr")
                
                let userName = Object1?["userName"]
                ...
                let kommentarCount = Object1?["kommentarCount"]
                let userID = Object1?["userID"]
                
                //print(userID!)
                
                ViewComments.commentIDNew = commentId as! String
                
                func wertBerechnen(completion: @escaping (String) -> Void) {
                    self.ref = Database.database().reference()
                    self.ref.child("user/\(userID!)").observeSingleEvent (of: .value, with: { (snapshot) in
                        let value = snapshot.value as? NSDictionary
                        let userImage = value?["picture"] as? String ?? ""
                        completion(userImage)
                    })
                }

                wertBerechnen { userImage in
                    let video = importComment(
                        userName: userName as! String, userGroup: userGroup as! String,
                        userComment: userComment as! String, userTime: userTime as! String,
                        userLikes: userLikes as! Int, commentId: commentId as! String, placeID: placeID as! String, kommentarCount: kommentarCount as? Int, userImage: userImage)
                    specificNameVideos.append(video)
                }
                
            }
            self.dic[name] = specificNameVideos
            let tem = Array(self.dic.values).flatMap { $0 } // You can also sort allComments with userTime property
            self.table = tem.sorted { $0.userTime! > $1.userTime! }
            self.tableView.reloadData()
        }
        myFeed.myArray1 = []
    }
}

问题分析

这个错误的核心是Firebase的数据库查询属于异步操作,observeSingleEvent的回调闭包是void类型,根本不允许用return返回值。你已经想到用completion回调来传递userImage,这个思路是对的,但当前代码存在时序问题:循环遍历子节点时,异步请求还没完成,就执行了self.dic[name] = specificNameVideos和表格刷新,导致specificNameVideos里的数据不完整。另外,代码里大量使用强制解包(!),很容易触发崩溃,需要优化。

修正方案

下面是调整后的代码,解决异步时序问题并优化稳定性:

func datenBankAbfrage() {
    print("datenbankabfrage getriggert")
    dic = [:]
    
    for name in myFeed.myArray1 {
        ref = Database.database().reference().child("placeID/\(name)")
        
        ref.observe(.value) { [weak self] snapshot in
            guard let self = self else { return }
            self.dic[name] = []
            var specificNameVideos = [importComment]()
            let dispatchGroup = DispatchGroup()
            
            for video in snapshot.children.allObjects as! [DataSnapshot] {
                // 用可选绑定替代强制解包,避免崩溃
                guard let object1 = video.value as? [String: Any],
                      let userTimeNum = object1["userTime"] as? NSNumber,
                      let userName = object1["userName"] as? String,
                      let userGroup = object1["userGroup"] as? String,
                      let userComment = object1["userComment"] as? String,
                      let userLikes = object1["userLikes"] as? Int,
                      let commentId = object1["commentId"] as? String,
                      let placeID = object1["placeID"] as? String,
                      let userID = object1["userID"] as? String else {
                    continue
                }
                
                // 时间格式处理,改用Swift原生Date类型
                let timestampDate = Date(timeIntervalSince1970: Double(userTimeNum)/1000)
                let dateFormatter = DateFormatter()
                dateFormatter.timeZone = .current
                dateFormatter.dateFormat = "dd.MM.YY hh:mm"
                let time = dateFormatter.string(from: timestampDate)
                print("\(time) Uhr")
                
                ViewComments.commentIDNew = commentId
                dispatchGroup.enter()
                
                // 调用外部定义的异步函数
                self.fetchUserImage(userID: userID) { userImage in
                    let kommentarCount = object1["kommentarCount"] as? Int
                    let videoModel = importComment(
                        userName: userName,
                        userGroup: userGroup,
                        userComment: userComment,
                        userTime: time,
                        userLikes: userLikes,
                        commentId: commentId,
                        placeID: placeID,
                        kommentarCount: kommentarCount,
                        userImage: userImage
                    )
                    specificNameVideos.append(videoModel)
                    dispatchGroup.leave()
                }
            }
            
            // 所有异步请求完成后再更新数据和刷新表格
            dispatchGroup.notify(queue: .main) {
                self.dic[name] = specificNameVideos
                let tem = Array(self.dic.values).flatMap { $0 }
                self.table = tem.sorted { $0.userTime ?? "" > $1.userTime ?? "" }
                self.tableView.reloadData()
            }
        }
    }
    
    myFeed.myArray1 = []
}

// 将获取用户头像的逻辑独立成外部函数,避免重复定义
private func fetchUserImage(userID: String, completion: @escaping (String) -> Void) {
    let userRef = Database.database().reference().child("user/\(userID)")
    userRef.observeSingleEvent(of: .value) { snapshot in
        let userData = snapshot.value as? [String: Any]
        let userImage = userData?["picture"] as? String ?? ""
        completion(userImage)
    }
}

关键优化点

  1. 异步时序控制:用DispatchGroup跟踪所有获取userImage的异步请求,确保所有数据都加载完成后再更新字典和刷新表格;
  2. 避免循环引用:在闭包中使用[weak self]和guard let self = self,防止内存泄漏;
  3. 稳定性提升:用可选绑定替代强制解包,避免因数据缺失导致的崩溃;
  4. 代码结构优化:将获取用户头像的逻辑独立成外部函数,避免在循环中重复定义函数,提升代码可读性;
  5. 现代Swift语法:替换NSDate、NSTimeZone为Swift原生的Date和TimeZone,符合现代开发规范。

内容的提问来源于stack exchange,提问作者submariner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 04:30:55