본문 바로가기

프로젝트/Twitter Clone App (w∕Firebase)

15. 기능구현 #4

기능구현 #4
ExploreView


ExploreView
| UserService > fetchUser

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)
        }
    }
}

UserService는 현재 fetchUser 메서드를 가지고 있다.
uid를 전달받아 일치하는 데이터를 반환하는 기능을 한다.
비슷한 방식으로 유저를 검색하도록 구현한다.

func fetchUsers(completion: @escaping([User]) -> Void) {

}

fetchUsers라는 이름의 메서드를 정의한다.
해당 메서드는 결과값을 completion에 전달해 추가적인 기능을 하도록 구현할 예정이다.

func fetchUsers(completion: @escaping([User]) -> Void) {
    var users = [User]()
}

전달할 데이터는 users 배열에 저장한다.

func fetchUsers(completion: @escaping([User]) -> Void) {
    var users = [User]()

    Firestore.firestore().collection("users").getDocuments { snapshot, _ in
        guard let documents = snapshot?.documents else {
            return
        }

        documents.forEach { document in
            guard let user = try? document.data(as: User.self) else {
                return
            }

            users.append(user)
        }

        completion(users)
    }
}

이후엔 fetchUser 메서드와 동일한 방식으로 데이터를 가져온 뒤 users에 저장해 completion에 전달하면 된다.

ExploreView
| ExploreViewModel

class ExploreViewModel: ObservableObject {
    @Published var users = [User]()
    let service = UserService()

    init() {
        fetchUsers()
    }

    func fetchUsers() {
        service.fetchUsers { users in
            self.users = users

            print("Users are \(users)")
        }
    }
}

ExploreView에서 사용할 ExploreViewModel을 구성한다.
생성자에서 호출할 수 있도록 메서드를 재정의 하고, Published로 선언된 users 배열에 결과를 저장한다.
이제 해당 ViewModel이 초기화 될 때 users에 사용자의 목록이 저장되고,
ViewModel의 users 속성으로 접근할 수 있다.

ExploreView
| UserRowView

struct UserRowView: View {
    var body: some View {
        HStack(spacing: 12) {
            Circle()
                .frame(width: 45, height: 45)

            VStack(alignment: .leading, spacing: 4) {
                Text("user1")
                    .font(.subheadline).bold()
                    .foregroundColor(.black)

                Text("almost admin")
                    .font(.subheadline)
                    .foregroundColor(.gray)
            }

            Spacer()
        }
        .padding(.horizontal)
        .padding(.vertical, 4)
    }
}

기존의 UserRowView는 사용자의 실제 데이터 대신 더미 데이터를 표시하고 있다.
지금부터는 실제 데이터를 받아와 표시할 수 있도록 코드를 수정한다.

import SwiftUI
import Kingfisher

struct UserRowView: View {
    var body: some View {
        HStack(spacing: 12) {
        .
        .
        .

UserRowView는 각 계정의 프로필 사진을 표시할 수 있어야 한다.
앞서 추가한 Kingfisher 패키지를 사용할 수 있도록 Kingfisher를 import 한다.

import SwiftUI
import Kingfisher

struct UserRowView: View {
    let user: User

    var body: some View {
        HStack(spacing: 12) {
        .
        .
        .

UserRowView에 표시할 사용자에 대한 정보를 전달받을 수 있게 User 형식의 user 파라미터를 선언한다.

struct UserRowView: View {
    let user: User

    var body: some View {
        HStack(spacing: 12) {
            KFImage(URL(string: user.profileImageUrl))
                .resizable()
                .scaledToFill()
                .clipShape(Circle())
                .frame(width: 45, height: 45)
                .
                .
                .

전달받은 user 파라미터의 profileImageUrl을 KFImage 메서드에 전달해 프로필사진을 받아 오고, 이를 표시한다.

struct UserRowView: View {
    let user: User

    var body: some View {
        HStack(spacing: 12) {
            KFImage(URL(string: user.profileImageUrl))
                .resizable()
                .scaledToFill()
                .clipShape(Circle())
                .frame(width: 45, height: 45)

            VStack(alignment: .leading, spacing: 4) {
                Text(user.username)
                    .font(.subheadline).bold()
                    .foregroundColor(.black)

                Text(user.fullname)
                    .font(.subheadline)
                    .foregroundColor(.gray)
            }
            .
            .
            .

계정명과 사용자 이름도 user의 username과 fullname 속성에 접근해 대체한다.

ExploreView
| ExploreView

struct ExploreView: View {
    @ObservedObject var viewModel = ExploreViewModel()
}

ExploreView는 앞서 구현한 ExploreViewModel을 ObservableObject 형식의 viewModel 인스턴스로 선언한다.
이 과정에서 유저들의 목록을 가져와 viewModel 인스턴스 안의 users에 저장한다.

struct ExploreView: View {
    @ObservedObject var viewModel = ExploreViewModel()

    var body: some View {
        VStack {
            ScrollView {
                LazyVStack {
                    ForEach(viewModel.users) { user in
                        NavigationLink {
                            ProfileView(user: user)
                        } label: {
                            UserRowView(user: user)
                        }
                    }
                }
            }
        }
        .navigationTitle("Explore")
        .navigationBarTitleDisplayMode(.inline)
    }
}

이제는 ExploreView에서 ProfileView와 UserRowView에 전달할 user가 존재하므로,
각각에 파라미터로 전달해 구성한다.

'프로젝트 > Twitter Clone App (w∕Firebase)' 카테고리의 다른 글

17. 기능 구현 #5  (0) 2023.01.12
16. 코드 가독성 개선  (0) 2023.01.11
14. 버그 수정 #1  (0) 2023.01.11
13. DB와 연결하기 #2  (0) 2023.01.10
12. DB와 연결하기 #1  (0) 2023.01.05