기능 구현 #8
TweetRowView 데이터 연결
TweetRowView 데이터 연결
| FeedViewModel
이전에 구현한 대로라면 FeedView가 표시되고, FeedViewModel을 호출하는 순간, fetchTweets 메서드가 작동하게 된다.
class FeedViewModel: ObservableObject {
@Published var tweets = [Tweet]()
let service = TweetService()
init() {
fetchTweets()
}
func fetchTweets() {
service.fetchTweets { tweets in
self.tweets = tweets
}
}
}
Tweet은 위와 같이 내용, 좋아요 카운트, 작성 날짜, 유저 정보(uid)를 가지고 있다.
필요한 정보를 전부 가지고 있는 것 같지만, 해당 유저의 계정, 이름, 프로필 사진 등 필요한 정보들은 존재하지 않는 상태다.
import Firebase
import FirebaseFirestoreSwift
struct UserService {
func fetchUser(withUid uid: String, completion: @escaping(User) -> Void) {
Firestore.firestore().collection("users").document(uid).getDocument { snapshot, _ in
guard let snapshot = snapshot else {
return
}
guard let user = try? snapshot.data(as: User.self) else {
return
}
completion(user)
}
}
func fetchUsers(completion: @escaping([User]) -> Void) {
Firestore.firestore().collection("users").getDocuments { snapshot, _ in
guard let documents = snapshot?.documents else {
return
}
let users = documents.compactMap({ try? $0.data(as: User.self) })
completion(users)
}
}
}
따라서 uid를 사용해 사용자의 정보를 가져 올 필요가 있고, 관련된 메서드는 이미 UserService에서 fetchUser로 구현한 바 있다.
class FeedViewModel: ObservableObject {
@Published var tweets = [Tweet]()
let service = TweetService()
let userService = UserService()
init() {
fetchTweets()
}
fetchUser 메서드를 사용할 수 있도록 FeedViewModel에 UserService 인스턴스를 생성한다.
Tweet를 받아오는 반환 값은 배열의 형태이며, 각각의 데이터는 Tweet 구조체로 이뤄져 있다.
struct Tweet: Identifiable, Codable {
@DocumentID var id: String?
let caption: String
let timestamp: Timestamp
let uid: String
var likes: Int
var user: User?
}
앞서 정의했던 Tweet 구조체는 DB에서 받아온 데이터를 SwiftUI에서 사용할 수 있도록 바인딩하는 역할을 한다.
그 와중에 아직 한 번도 사용하지 않았고, DB에 저장돼 있은 Tweet의 데이터도 아닌 변수가 하나 존재하는데,
바로 user다.
func fetchTweets() {
service.fetchTweets { tweets in
self.tweets = tweets
for i in 0 ..< tweets.count {
let uid = tweets[i].uid
self.userService.fetchUser(withUid: uid) { user in
self.tweets[i].user = user
}
}
}
}
DB에서 받아 온 Tweet 배열을 하나씩 열거하며
작성자의 uid를 fetchUser 메서드에 전달해 작성자의 실제 정보를 user 변수에 저장한다.
TweetRowView 데이터 연결
| FeedRowView
before
var body: some View {
VStack(alignment: .leading) {
//profile image & user info & tweet
HStack(alignment: .top, spacing: 12) {
Circle()
.frame(width: 56, height: 56)
.foregroundColor(Color(.systemBlue))
//user info & tweet caption
VStack(alignment: .leading, spacing: 4) {
//user info
HStack {
Text("Marcus")
.font(.subheadline).bold()
Group {
Text("@philosophy")
Text("2d")
}
.foregroundColor(.gray)
.font(.caption)
}
//tweet caption
Text(tweet.caption)
.font(.subheadline)
.multilineTextAlignment(.leading)
}
}
.
.
.
after
var body: some View {
VStack(alignment: .leading) {
//profile image & user info & tweet
if let user = tweet.user {
HStack(alignment: .top, spacing: 12) {
KFImage(URL(string: user.profileImageUrl))
.resizable()
.scaledToFill()
.clipShape(Circle())
.frame(width: 56, height: 56)
//user info & tweet caption
VStack(alignment: .leading, spacing: 4) {
//user info
HStack {
Text(user.fullname)
.font(.subheadline).bold()
Group {
Text("@\(user.username)")
Text("2d")
}
.foregroundColor(.gray)
.font(.caption)
}
//tweet caption
Text(tweet.caption)
.font(.subheadline)
.multilineTextAlignment(.leading)
}
}
}
.
.
.
모든 준비는 끝났다.
실제 데이터를 각각에 전달해 올바르게 표시하기만 하면 된다.
결과
'프로젝트 > Twitter Clone App (w∕Firebase)' 카테고리의 다른 글
22. 버그수정 #2 (0) | 2023.01.18 |
---|---|
21. DB와 연결하기 #3 (0) | 2023.01.18 |
19. 기능 구현 #7 (0) | 2023.01.14 |
18. 기능 구현 #6 (0) | 2023.01.13 |
17. 기능 구현 #5 (0) | 2023.01.12 |