[UIKit] BlogClone: Posting

Junyoung Park·2022년 11월 24일
0

UIKit

목록 보기
101/142
post-thumbnail
post-custom-banner

Building Subscription Blogging App: Part 7 – Creating Posts (2021, Xcode 12, Swift 5) – iOS

BlogClone: Posting

구현 목표

  • 블로그 포스팅

구현 태스크

  • 포스팅 데이터 구성
  • 포스팅 셀 UI 구현
  • 데이터베이스 등록 및 데이터 패치

핵심 코드

output
            .sink { [weak self] result in
                switch result {
                case .isPosted(let result): self?.handlePost(result)
                case .isTitleEmpty:
                    self?.showAlert("Fill in your post title.")
                case .isTextEmpty:
                    self?.showAlert("Fill in your post text.")
                case .isAllEmpty:
                    self?.showAlert("Fill in your title and text.")
                }
            }
            .store(in: &cancellables)
  • 포스트 작성 뷰에서 뷰 모델이 내보내는 아웃풋을 구독한 부분
  • 포스트가 완료되었다면 현재 뷰를 내림
private func uploadPost(data: [String: Any], completion: @escaping(Bool) -> Void) {
        Firestore.firestore().collection("posts").document()
            .setData(data) { error in
                if let error = error {
                    print(error.localizedDescription)
                    completion(false)
                } else {
                    print("Upload Post Did Succeed")
                    completion(true)
                }
            }
    }
    
    func uploadPost(title: String, text: String, headerImage: UIImage?, completion: @escaping(Bool) -> Void) {
        guard let uid = Auth.auth().currentUser?.uid else { return }
        var data:[String:Any] = [
            "uid": uid,
            "title": title,
            "text": text,
            "timestamp": Timestamp(date: Date())
        ]
        if let headerImage = headerImage {
            ImageUploader.uploadImage(image: headerImage, folder: .postHeader) { result in
                switch result {
                case .success(let urlString):
                    data["headerImageURL"] = urlString
                    uploadPost(data: data, completion: completion)
                case .failure(let error): print(error.localizedDescription)
                }
            }
        } else {
            uploadPost(data: data, completion: completion)
        }
    }
  • 입력된 타이틀, 텍스트, 헤더 이미지를 통해 새로운 포스트를 생성 및 현재 유저의 uid로 입력하는 함수
  • 이미지 유무에 따라서 이미지를 업로드한 결과 문자열을 리턴
  • 업로드 완료 결과를 컴플리션 핸들러를 통해 곧바로 리턴
func fetchPosts(completion: @escaping(Result<[PostModel], Error>) -> Void) {
        Firestore.firestore().collection("posts")
            .order(by: "timestamp", descending: true)
            .getDocuments { snapshot, error in
                guard
                    let documents = snapshot?.documents,
                    error == nil else {
                    completion(.failure(DatabaseError.fetchBlogDidFail))
                    return
                }
                let posts = documents.compactMap({try? $0.data(as: PostModel.self)})
                completion(.success(posts))
            }
    }
  • 프로필 뷰에서 현재 유저가 작성한 포스트만을 리턴하는 함수
func fetchPosts() {
        guard let uid = Auth.auth().currentUser?.uid else { return }
        service.fetchPosts(for: uid) { [weak self] result in
            switch result {
            case .failure(let error): print(error.localizedDescription)
            case .success(let posts): self?.posts.send(posts)
            }
            self?.output.send(.fetchResultReturend)
        }
    }
  • 프로필 뷰 모델에서 포스트 테이블 뷰에 사용할 데이터를 얻기 위해 데이터를 가져오는 함수
tableView.refreshControl = UIRefreshControl()
        tableView.refreshControl?.addTarget(self, action: #selector(pullToRefresh), for: .valueChanged)
  • 테이블 뷰 자체 제공 리프레시 기능 사용
@objc private func pullToRefresh() {
        input.send(.didPullToRefresh)
    }
  • 뷰 모델에게 현재 유저가 작성한 포스트를 패치해오라는 명령
output
            .sink { [weak self] result in
                switch result {
                case .fetchResultReturend:
                    self?.tableView.refreshControl?.endRefreshing()
                }
            }
            .store(in: &cancellables)
  • 데이터베이스 패치가 완료된다면 테이블 뷰 리프레시를 멈추기 위한 코드

구현 화면

파이어스토어에 스냅샷 리스너를 달아 특정 유저가 작성한 포스트를 읽어올 수도 있겠지만, 리프레시 컨트롤을 사용해보고자 했다.

profile
JUST DO IT
post-custom-banner

0개의 댓글