我具有-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
}
答案 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检索数据通常不是一个好主意,因为它会使应用程序运行缓慢并且用户体验差。预加载您的所有数据,以保持表格视图的活泼。