如何以正确的方式从Firebase数据库加载图像

时间:2019-12-28 08:37:25

标签: ios swift xcode firebase firebase-realtime-database

我具有-post和-user的数据库结构,在post下,我具有发布信息,即发布图像,文本数据和发布它的用户的uid。在用户节点中,我具有包含该用户的个人资料图片的用户信息。

现在,我正在尝试检索帖子以及用户的个人资料图片。我能够检索帖子,但无法正确加载个人资料图像,我尝试了许多不同的方法,当计数等于等于重新加载tableview时,代码中的一个具有2个索引,这会产生冲突并加载图像即使数量相同,也以随机的方式。任何想法,我都可以加载图像,以便它们与正确的帖子相对应。我是Firebase的新手。

func postRetrieve()  {
SVProgressHUD.show()
let ref = Database.database().reference()
ref.child("posts").queryOrdered(byChild: "timesStamp").observeSingleEvent(of: .value) { (snapshot) in
    let post = snapshot.value as! [String : AnyObject]
    self.userPost.removeAll()

    for (_ , value ) in post {
        if let usersId = value["userID"] as? String  {
            self.usersKey.append(usersId)
            print("here toooo")
            let finalPostToShow = Post()
            if let topicData = value["topic"] as? String,
                let userName = value["creator"] as? String,
                let timeStamp = value["timesStamp"] as? Double

                {
                finalPostToShow.topicData = topicData
                finalPostToShow.usrId = usersId
                finalPostToShow.userName = userName

                self.userPost.append(finalPostToShow)
            }
        }
        print("there are \(self.userPost.count) posts")

    }
     guard self.userPost.count != self.userCred.count else {
            print("loading cells now 01")
            return self.TableViewControllerHome.reloadData()}
}
ref.removeAllObservers()}

用于加载个人资料图片的代码分别称为:

func profileImage() {
    let ref = Database.database().reference()
    ref.child("users").queryOrdered(byChild: "timesStamp").observeSingleEvent(of: .value) { (dataSnapshots) in
        let usersnap = dataSnapshots.value as? [String : AnyObject]
        self.userCred.removeAll()
        for (_,value) in usersnap! {
            if let userIdKey = value["uid"] as? String {
                let finalUserToShow = user()
                for each in self.usersKey {
                    if each == userIdKey {
                        if let userPhotoImg = value["urlToImage"] as? String{
                            finalUserToShow.ImagePath = userPhotoImg
                            self.userCred.append(finalUserToShow)
                        }
                    }
                    print(finalUserToShow)
                    print("there are   \(self.userCred.count) profile photos")
                }
            }
        }
    }
}

我的firebase结构:

"posts" : {
"-LwxPtjQh6Sq9cMw-XSO" : {
  "attachedUsers" : [ "BtJEpoob3CPR1EN1nFRiUj6uKIX2", "OtipKVdgmyNNR9eGwVFBqyYrvL93", "PV3NEJhepRZQiNHJ7H7KO9aWGy62", "wt4PZb6UUtbeUI2v2SFRZ9hZBNt1" ],
  "content" : "The 2019 Range Rover Autobiography delivers 16 mpg in ",
  "creator" : "Mac",
  "description" : "Rangerover  ",
  "likes" : 0,
  "pathToImage" : "https://firebasestorage.googleapis.com/v0/b/neighbors-3a1df.appspot.com/o/posts%2Fssb9HIqEp4SxPuUZSJDUfYYLKPS2%2F-LwxPtjQh6Sq9cMw-XSO.jpeg?alt=media&token=8a87777f-d2c4-4fb9-8c7d-89b5fb0ef042",
  "timesStamp" : 1577283495118,
  "topic" : "Rangerover",
  "userID" : "ssb9HIqEp4SxPuUZSJDUfYYLKPS2",
  "views" : 0,
  "webUrl" : "https://www.landrover.in/index.html"
}
    "-Lx0z-1LlbIhpBFGNIfW" : {
  "attachedUsers" : [ "X0kiMno8EEclwlVvVymNK00wNw52", "OtipKVdgmyNNR9eGwVFBqyYrvL93", "38nPNJujqpeovv558FeFHqB90Qu2", "0NQbltVlx3d3yOwich9IXntyBqD3" ],
  "content" : "The  been",
  "creator" : "Mac",
  "description" : "Cybertruck ",
  "likes" : 0,
  "mainImages" : {
    "-Lx0z0_Nc6FIA_flu_Eq" : "https://firebasestorage.googleapis.com/v0/b/neighbors-3a1df.appspot.com/o/posts%2Fssb9HIqEp4SxPuUZSJDUfYYLKPS2%2F-Lx0z0_Nc6FIA_flu_Eq.jpeg?alt=media&token=becde9e1-ca9d-4e98-98ce-e1aa5edeede2",
    "-Lx0z0_T1uxgmU8DCVda" : "https://firebasestorage.googleapis.com/v0/b/neighbors-3a1df.appspot.com/o/posts%2Fssb9HIqEp4SxPuUZSJDUfYYLKPS2%2F-Lx0z0_T1uxgmU8DCVda.jpeg?alt=media&token=3b71bca8-8988-481f-994c-41e07fde6972"
  },
  "pathToImage" : "https://firebasestorage.googleapis.com/v0/b/neighbors-3a1df.appspot.com/o/posts%2Fssb9HIqEp4SxPuUZSJDUfYYLKPS2%2F-Lx0z-1LlbIhpBFGNIfW.jpeg?alt=media&token=0108e73d-3e34-4137-8729-7e826166d871",
  "timesStamp" : 1577360038766,
  "topic" : "Madness",
  "userID" : "ssb9HIqEp4SxPuUZSJDUfYYLKPS2",
  "views" : 0,
  "webUrl" : ""
},




"users" : {
"0NQbltVlx3d3yOwich9IXntyBqD3" : {
  "dateJoined" : 1541925226084,
  "followers" : {
    "-LR2KlE95CjaV6NLh36e" : "DjyEuBBc3YRGq8lZ1AmDxtUOUNq1",
    "-LRP2W1XXhB1oerC2LJu" : "2EWMigIqM2hObmRQqFgR60T9L5r1",
    "-LTHvpSl8tcVWJs8Gyef" : "9zqI9O8uU1VdeysJ8p0F51AVQG13",
    "-LTTrN2UxHRMkaoZdOJj" : "jeCBp7JvXhhV1hyBCW6pGSdJWxo2",
    "-Lf_gGCB_1nWpfQNIf6d" : "38nPNJujqpeovv558FeFHqB90Qu2",
    "-LtPH3HCtgkT5j2Xq7Hk" : "ssb9HIqEp4SxPuUZSJDUfYYLKPS2"
  },
  "full Name" : "Warren Buffett",
  "uid" : "0NQbltVlx3d3yOwich9IXntyBqD3",
  "urlToImage" : "https://firebasestorage.googleapis.com/v0/b/neighbors-3a1df.appspot.com/o/users%2F0NQbltVlx3d3yOwich9IXntyBqD3.jpg?alt=media&token=673f8326-870e-496c-89ee-3ad9c06693ca"
},

加载图像的功能:

class CustomImageView : UIImageView {
func loadImagesWithUrl(from imageUrl : String!)  {
    self.image = nil

    if let cachedImage = imageCache.object(forKey: imageUrl as AnyObject) as? UIImage {
        self.image = cachedImage
        return
    }

    let url = URLRequest(url: URL(string: imageUrl)!)
    URLSession.shared.dataTask(with: url) { (data, response, eror) in

        if eror != nil {
            print(eror!)
            return
        }

            DispatchQueue.main.async {
            if let downloadedImage = UIImage(data : data!) {
                imageCache.setObject(downloadedImage, forKey: imageUrl as AnyObject)
                self.image = downloadedImage
            }
        }
    }.resume()
}

}

我的tableview cellForRowAt:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   let cellData =  TableViewControllerHome.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! viewControllerHomeCell

   cellData.writingfrom.setTitle(self.userPost[indexPath.row].topicData, for: .normal)
    cellData.profileImage.loadImagesWithUrl(from:self.userCred[indexPath.row].ImagePath)
    cellData.profileName.text = userPost[indexPath.row].userName
    cellData.dateCreated.text = userPost[indexPath.row].dateCreated
    cellData.userID = userPost[indexPath.row].usrId


    return cellData
}

1 个答案:

答案 0 :(得分:0)

此答案分为两部分:一是显示示例代码,以演示如何处理数据流。第二个是显示如何大大缩短和收紧代码,因为问题中有很多无关的代码。

在您正在处理帖子的问题中-这个答案几乎是同一回事;我们将遍历用户节点并将用户名和个人资料图像加载到tableView中。名称存储在Firebase实时数据库中,图像存储在Firebase存储中(强烈建议使用该API,因为API非常棒)。

因此,让我们从一个类开始存储用户名(例如,您的帖子文本),然后存储个人资料图像。请注意,在某些情况下图像可能为零,因此我们需要在tableView刷新时处理这些情况。

class UserNameAndImageClass {
    var uid = ""
    var name = ""
    var image: NSImage?

    init(withName: String, andUid: String, andImage: NSImage?) {
        self.name = withName
        self.uid = andUid
        self.image = andImage
    }
}

,然后使用一个类级别的var数组作为tableView的数据源

var userNameAndImageArray = [UserNameAndImageClass]()

,然后读取所有数据并填充dataSouce的代码,完成后重新加载tableView

func fetchUsersAndImages() {
    let storage = Storage.storage()
    let storageRef = storage.reference()
    let imagesRef = storageRef.child("images") //where the profile images are stored

    let usersRef = self.ref.child("users")
    usersRef.observeSingleEvent(of: .value, with: { snapshot in
        let lastIndex = snapshot.childrenCount - 1 //how many total child nodes
        var currentIndex = 0 //used to trigger the reload when all data has been read

        //Assign all of the child nodes to an array of DataSnapshots. This keeps them in
        //  order and also maintains each child node as a DataSnapshot making it easier to
        //  access other child data within each node
        let allUsersSnap = snapshot.children.allObjects as! [DataSnapshot]                                                
        for userSnap in allUsersSnap {
            let uid = userSnap.key
            let name = userSnap.childSnapshot(forPath: "name").value as? String ?? "No Name"
            let profileImageName = "\(uid).png"
            let picRef = imagesRef.child(profileImageName)

            //Firebase Storage code here - insert your own if needed
            picRef.getData(maxSize: 1 * 1024 * 1024) { data, error in // Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
                var aImage: NSImage?
                if let imageData = data { //data could be nil
                    aImage = NSImage(data: imageData)
                }

                let aUser = UserNameAndImageClass(withName: name, andUid: uid, andImage: aImage)
                self.userNameAndImageArray.append(aUser)

                if currentIndex == lastIndex { //if we've loaded all of the users and their images, refresh the UI
                    self.myTableView.reloadData()
                }

                currentIndex += 1
            }
        }
    })
}

一些注意事项。

在用户节点中,您将用户uid存储为节点以及子节点的密钥。没有理由这样做-将其存储为密钥!如果您读取了该节点,则始终可以使用以下快照来访问密钥:

let uid = userSnap.key

在读取图片的部分中,请注意我正在使用一个简单的计数器,该计数器一直等到我们读完最后一张图片后再更新UI。它们将减少闪烁。有些人建议为此任务使用一个调度组,该调度组也可以正常工作。

使用.observeSingleEvent之后,您无需删除AllObservers,因为它只会触发一次并且不会离开观察者。

最后,也许是最重要的事情:不要对tableView函数进行任何繁重的操作!它们应该是快速,轻量级的,并具有最少的代码。在单元格或tableView函数中从Internet检索数据通常不是一个好主意,因为它会使应用程序运行缓慢并且用户体验差。预加载您的所有数据,以保持表格视图的活泼。