只要调用“fetchfollowingposts”函数,提要单元格中的用户信息就会发生变化。我已经使用用户的 uid 将帖子保存到 firebase,并且我正在尝试从绑定到帖子的 uid 中获取他们的个人资料照片、全名等。每当我刷新提要视图时,用户的信息都会发生变化,但帖子本身永远不会改变(时间戳、帖子标题、帖子图片、喜欢)。
因为我不完全理解这个问题,所以我不确定需要什么文件,所以如果我错过了一个,请告诉我。预先感谢您的帮助!
FeedCellView
import SwiftUI
import Kingfisher
struct FeedCell: View {
@ObservedObject var viewModel: FeedCellViewModel
@State private var isShowingBottomSheet = false
var didLike: Bool { return viewModel.post.didLike ?? false }
@Environment(\.presentationMode) var mode
init(viewModel: FeedCellViewModel) {
self.viewModel = viewModel
}
var body: some View {
VStack (alignment: .leading, spacing: 16) {
NavigationLink {
if let user = viewModel.post.user {
LazyView(ProfileView(user: user))
}
} label: {
HStack (alignment: .top) {
KFImage(URL(string: viewModel.post.user?.profileImageUrl ?? "https://firebasestorage.googleapis.com/v0/b/pageturner-951b4.appspot.com/o/profile_image%2FNoProfilePhoto.png?alt=media&token=1055648d-4d6e-4d51-b003-948a47b6bb76"))
.resizable()
.scaledToFill()
.frame(width: 48, height: 48)
.cornerRadius(10)
VStack (alignment: .leading, spacing: 4) {
Text(viewModel.post.user?.fullname ?? "")
.font(.system(size: 16))
.foregroundColor(Color(.label))
Text(viewModel.timestampString)
.font(.system(size: 14))
.foregroundColor(.gray)
}
Spacer()
if viewModel.post.isCurrentUser {
Button {
isShowingBottomSheet.toggle()
} label: {
Image(systemName: "ellipsis")
}.foregroundColor(Color(.gray))
.confirmationDialog("What do you want to do?",
isPresented: $isShowingBottomSheet) {
Button("Delete post", role: .destructive) {
viewModel.deletePost()
}
} message: {
Text("You cannot undo this action")
}
}
}
}
Text(viewModel.post.caption)
.font(.system(size: 16))
if let image = viewModel.post.imageUrl {
KFImage(URL(string: image))
.resizable()
.scaledToFill()
.frame(maxHeight: 250)
.cornerRadius(10)
}
HStack {
HStack (spacing: 24) {
Button {
didLike ? viewModel.unlike() : viewModel.like()
} label: {
Image(didLike ? "heart.fill" : "heart")
.renderingMode(.template)
.resizable()
.foregroundColor(didLike ? Color.accentColor : .black)
.frame(width: 24, height: 24)
Text("\(viewModel.post.likes)")
}
NavigationLink {
CommentView(post: viewModel.post)
} label: {
Image("comment")
.renderingMode(.template)
.resizable()
.frame(width: 24, height: 24)
Text("\(viewModel.post.stats?.CommentCount ?? 0)")
}
}
Spacer()
}
.foregroundColor(Color(.label))
}
}
}
FeedService
import SwiftUI
import FirebaseCore
import FirebaseAuth
import FirebaseFirestore
import FirebaseFirestoreSwift
struct FeedService {
func uploadPost(caption: String, image: UIImage?, completion: @escaping(Bool) -> Void) {
guard let uid = Auth.auth().currentUser?.uid else { return }
ImageUploader.uploadImage(image: image, type: .post) { imageUrl in
let data = ["uid": uid,
"caption": caption,
"likes": 0,
"imageUrl": imageUrl,
"timestamp": Timestamp(date: Date())] as [String: Any]
COLLECTION_POSTS.document()
.setData(data) { error in
if let error = error {
print("DEBUG: Failed to upload post with error: \(error.localizedDescription)")
completion(false)
return
}
}
completion(true)
}
}
func fetchFollowingPosts(forUid uid: String, completion: @escaping([Post]) -> Void) {
var posts = [Post]()
COLLECTION_FOLLOWING.document(uid).collection("user-following")
.getDocuments { snapshot, _ in
guard let documents = snapshot?.documents else { return }
documents.forEach { doc in
let userId = doc.documentID
COLLECTION_POSTS.whereField("uid", isEqualTo: userId)
.getDocuments { snapshot, _ in
guard let documents = snapshot?.documents else { return }
let post = documents.compactMap({ try? $0.data(as: Post.self) })
posts.append(contentsOf: post)
completion(posts.sorted(by: { $0.timestamp.dateValue() > $1.timestamp.dateValue()
}))
}
}
}
}
func uploadStory(caption: String?, image: UIImage, rating: Int?, completion: @escaping(Bool) -> Void) {
guard let uid = Auth.auth().currentUser?.uid else { return }
ImageUploader.uploadImage(image: image, type: .story) { imageUrl in
let data = ["uid": uid,
"caption": caption ?? "",
"imageUrl": imageUrl,
"rating": rating ?? "",
"isSeen": false,
"timestamp": Timestamp(date: Date())] as [String: Any]
COLLECTION_STORIES.document()
.setData(data) { error in
if let error = error {
print("DEBUG: Failed to upload story with error: \(error.localizedDescription)")
completion(false)
return
}
}
completion(true)
}
}
func fetchFollowingStories(forUid uid: String, completion: @escaping([Story]) -> Void) {
var stories = [Story]()
COLLECTION_FOLLOWING.document(uid).collection("user-following")
.getDocuments { snapshot, _ in
guard let documents = snapshot?.documents else { return }
documents.forEach { doc in
let userId = doc.documentID
COLLECTION_STORIES.whereField("uid", isEqualTo: userId)
.getDocuments { snapshot, _ in
guard let documents = snapshot?.documents else { return }
let story = documents.compactMap({ try? $0.data(as: Story.self) })
stories.append(contentsOf: story)
completion(stories.sorted(by: { $0.timestamp.dateValue() > $1.timestamp.dateValue()
}))
}
}
}
}
}
FeedViewModel
import SwiftUI
class FeedViewModel: ObservableObject {
@Published var followingPosts = [Post]()
@Published var followingStories = [Story]()
let service = FeedService()
let userService = UserService()
init() {
fetchFollowingPosts()
fetchFollowingStories()
}
func fetchFollowingPosts() {
guard let userid = AuthViewModel.shared.userSession?.uid else { return }
service.fetchFollowingPosts(forUid: userid) { posts in
self.followingPosts = posts
for i in 0 ..< posts.count {
let uid = posts[i].uid
self.userService.fetchUser(withUid: uid) { user in
self.followingPosts[i].user = user
}
}
}
}
func fetchFollowingStories() {
guard let userid = AuthViewModel.shared.userSession?.uid else { return }
service.fetchFollowingStories(forUid: userid) { stories in
self.followingStories = stories
for i in 0 ..< stories.count {
let uid = stories[i].uid
self.userService.fetchUser(withUid: uid) { user in
self.followingStories[i].user = user
}
}
}
}
}