[iOS, Firebase] 파이어 베이스 기초 활용법

Updated:

파이어베이스란?

  • 관계형 데이터베이스가 아닌 NoSQL 데이터베이스 기반의 클라우드 서비스를 제공하는 플랫폼

  • 인증, 푸시 알림 등의 다양한 기능을 가진 가진 라이브러리를 제공

파이어베이스 라이브러리

파이어베이스에는 다양한 기능의 API 함수들을 사용할 수 있게 해주는 많은 라이브러리를 제공한다. 그 중에서 앱을 만든다면 필수라고 생각되는 단 세개의 라이브러리의 소개와 활용법을 소개하고자 한다.

  • FirebaseAuth : 인증

  • FirebaseFirestore : 데이터 저장

  • FirebaseStorage : 파일 저장소

FirebaseAuth 라이브러리

사용자 인증기능을 사용할 수 있게 해주는 라이브러리이다. 가입에서부터 로그인까지 폭넓은 인증에 관한 API 함수를 제공한다. 이메일을 가장 기본으로 계정을 생성하며, 흔히 사용되는 API 함수는 다음과 같다.

  • 가입: Auth.auth().createUser(withEmail:password:completion:)

  • 로그인: Auth.auth().signIn(withEmail:password:completion:)

  • 로그아웃: Auth.auth().signOut()

우선 이 포스팅에서는 이메일로 회원관리를 하는 코드들을 선보일 것이기에 다음과 같은 설정이 되어있어야 한다.

사전에 사용 예를 보이기 전에 register, login, logout 메서드는 AuthViewController 에서 다뤄지고 있는 걸로 하겠다.

class AuthViewController {

    var userSession: FirebaseAuth.User? // 파이어베이스 유저 객체
    var currentUser: User? // 유저 모델
    
    static let shared = AuthViewController()
    
    init() {
      userSession = Auth.auth().currentUser // 파이어베이스의 유저 정보를 가져옴(로그인 되있는 상태가 아니면 nil)
    }
    .
    .
    .


가입

Auth.auth().createUser(withEmail:password:completion:)

func register(withEmail email: String, password: String) {

    Auth.auth().createUser(withEmail: email, password: password) { result, error in
        if let error = error { // 로그인 실패시 메시지 출력
            print("DEBUG: \(error.localizedDescription)")
            return
        }
        
        /*
         추가 코드, 밑에서 FirebaseFirestore 다룰때 추가함
        */
    }
}

회원가입에 성공하게 되면 파이어베이스 유저 계정 목록에 하나하나 추가가 된다. 물론 비밀번호는 표시되지 않는다.


로그인

Auth.auth().signIn(withEmail:password:completion:)
파이어베이스 사용자 계정에 등록된 유저라면 로그인 할 수 있다.

func login(withEmail email: String, password: String) {

    Auth.auth().signIn(withEmail: email, password: password) { result, error in
        if let error = error { // 로그인 실패시 메시지 출력
            print("DEBUG: \(error.localizedDescription)")
            return
        }
        .
        .
        .
    }
}


로그아웃

Auth.auth().signOut()

func logout() { 
    try? Auth.auth().signOut()
}


FirebaseFirestore 라이브러리

데이터를 파이어베이스 NoSql 데이터베이스에 저장하거나 혹은 데이터베이스로부터 데이터를 가져올 수 있는 API 함수들을 제공한다. 해당 API 함수들을 사용하려면 파이어베이스에서 데이터가 어떤 구조로 저장되는지 이해해야 한다.

  • collection: document(문서)들을 가진다

  • document: 필드들을 가지며, 새로운 collection을 가질 수 있다.

  • 필드: 데이터

사진으로 보도록 하자

위처럼 계속해서 컬렉션과 도큐먼트, 필드 데이터를 추가해줄 수 있다. 여기서 눈여겨 봐야 할것은 저 Document ID 이다. 이 Document ID는 임의로 우리가 지정해 줄 수 있고 지정하지 않고 파이어베이스에서 알아서 생성하게 할 수도 있다. 이 두 차이점은 아래에서 다루도록 하겠다. 구조를 대강 어느 정도 봤으니 FirebaseFirestore 라이브러리에서 자주 사용하는 API 들을 정리하자면 다음과 같다.

  • 하나의 데이터 저장_1: Firestore.firestore().collection({컬렉션 이름}).document({DocumentID}).setData(_:completion:)

  • 하나의 데이터 저장_2: Firestroe.firestore().collection({컬렉션 이름}).addDocument(data:completion:)

  • 하나의 데이터 가져오기: Firestore.firestore().collection({컬렉션 이름}).document({documentID}).getDocument(completion:)

  • 모든 데이터 가져오기: Firestore.firestore().collection({컬렉션 이름}).getDocuments(completion:)

이제 위에서 작성했던 register 함수를 확장시켜 보자.

하나의 데이터 저장_1, 하나의 데이터 가져오기

  • 하나의 데이터 저장_1: Firestore.firestore().collection({컬렉션 이름}).document({DocumentID}).setData(_:completion:)

  • 하나의 데이터 가져오기: Firestore.firestore().collection({컬렉션 이름}).document({documentID}).getDocument(completion:)

  • 회원가입을 하게 되면 그 사용자에 대한 UID가 생성된다. 그리고 이 UID는 그 사용자 정보를 데이터베이스에 저장할 때 DocumentID로 지정하여 통일성 및 유일성을 줘야한다.


func register(withEmail email: String, password: String, username: String, fullname: String) {
    Auth.auth().createUser(withEmail: email, password: password) { result, error in
        if let error = error {
            print("DEBUG: \(error.localizedDescription)")
            return
        }

        guard let user = result?.user else { return } // 파이어베이스 유저 객체를 가져옴
        
        // 전달할 데이터
        let data = ["email": email, 
                    "username": username,
                    "fullname": fullname
        ]
        
        // 가입에 성공하면 그 유저의 uid를 파이어베이스가 생성해준다.
        // 그렇기 때문에 이 uid를 기준으로 특정한 유저 데이터를 저장해야 한다.
        Firestore.firestore().collection("user").document(user.uid).setData(data) { error in
            if let error = error {
                print("DEBUG: \(error.localizedDescription)")
                return
            }

            self.userSession = user // 가입하면 바로 로그인 되도록 세션 등록

            Firestore.firestore().collection("user").document(user.uid).getDocument { snapshot, error in
                guard let userData = try? snapshot?.data(as: User.self) else { return } // 매핑(FirebaseFirestoreSwift 라이브러리를 추가해야 사용가능)

                self.currentUser = userData
            }
        }
    }
}


하나의 데이터 저장_2

Firestroe.firestore().collection({컬렉션 이름}).addDocument(data:completion:)

회원가입으로 인해 자동으로 이미 생성된 사용자 UID 를 기준으로 documentID를 지정해줘야 하는 경우가 아니라면 다음과 같이 단순하게 데이터만 추가해주면 자동으로 documentID가 할당된다.

func uploadPost(caption: String, ownerName: String, ownerUid: String) {
    let data = ["caption": caption,
                "ownerName": ownerName,
                "ownerUid": ownerUid
    ]

    Firestore.firestore().collection("post").addDocument(data: data) { error in
        if let error = error {
            print("DEBUG: \(error.localizedDescription)")
            return
        }
        .
        .
        .
    }
}


모든 데이터 가져오기

Firestore.firestore().collection({컬렉션 이름}).getDocuments(completion:)

func getUsers() {
    Firestore.firestore().collection("user").getDocuments { snapshot, error in
        if let error = error {
            print("DEBUG: \(error.localizedDescription)")
            return
        }

        guard let documents = snapshot?.documents else { return } // document들을 가져옴

        let users = documents.compactMap( { try? $0.data(as: User.self) }) // User 구조체로 전부 매핑
        .
        .
        .
    }
}


FirebaseStorage 라이브러리

이미지, 영상, 문서등의 파일들을 저장할 수 있도록 해주는 API 함수들을 제공한다. FirebaseStorage에서 제공하는 API를 이용하여 파일을 저장하면 파이어베이스 관리자 페이지에서는 아래와 같이 구조가 이루어진다.


여기서는 사진을 저장하고 저장한 사진의 Url 주소를 가져오는 API함수를 다뤄보도록 한다.

  • 파일 저장: Storage.storage().reference(withPath:).putData(_:metadata:completion:)
  • 파일 URL: Storage.storage().reference(withPath:).downLoadURL(completion:)
func uploadImage(image: UIImage) {

    // jpeg 파일의 퀄리티를 반으로 해서 가져오기, jpege 파일이 아니면 리턴
    guard let imageData = image.jpegData(compressionQuality: 0.5) else { return }

    // E621E1F8-C36C-495A-93FC-0C247A3E6E5F 형식으로 이미지 이름 짓기
    let filename = NSUUID().uuidString
    let ref = Storage.storage().reference(withPath: "폴더이름은/알아서지어요/\(filename)")

    // 이미지 업로드 하기
    ref.putData(imageData, metadata: nil) { data, error in
        if let error = error {
            print("DEBUG: \(error.localizedDescription)")
            return
        }

        // 업로드한 이미지 url 가져오기
        ref.downloadURL { url, _ in
            guard let imageUrl = url?.absoluteString else { return }

            print("URL: \(imageUrl)")
        }
    }
}

Leave a comment