[Swift 5] Implementation of membership registration with Firebase

Introduction

I am creating a LINE clone application for learning Firebase and chat function, and I will post the implementation of membership registration using Firebase as a memorandum. I am a beginner, so if you have any corrections, please point them out.

Overview

This time, in implementing the membership registration function, the order is as follows.

    1. User registration to FirebaseAuth
  1. Register your profile image in Firebase Storage
    1. Register user information in Firebase Firestore

--Registration is possible (new registration button is valid) if all of email address, password, and username are filled in. --1. When processing , after completing the membership registration using the approval email2. It seems that it is a common method to move to the processing of, but since the purpose of this time was for learning, that area is not considered.

Execution environment

【Xcode】Version 12.0.1 【Swift】Version 5.3 【CocoaPods】version 1.9.3 【Firebase】version 6.29.0

Screen after mounting

sample.gif

Implementation code

SignUpModel.swift


import Foundation
import Firebase

//delegate wants to weak reference, so inherit class
protocol SignUpModelDelegate: class {
    func createImageToFirestorageAction()
    func createUserToFirestoreAction(fileName: String?)
    func completedRegisterUserInfoAction()
}

class SignUpModel {
    
    //delegate references weak to avoid memory leak
    weak var delegate: SignUpModelDelegate?
    
    func createUser(email: String, password: String) {
        //Save to Firebase Auth
        Auth.auth().createUser(withEmail: email, password: password) { (res, err) in
            if let err = err {
                print("Failed to save to Firebase Auth.\(err)")
                //Processing when registration of user information fails
                return
            }
            print("Successfully saved to Firebase Auth.")
            //Completed saving to Firebase Auth->Save to Firebase Storage
            self.delegate?.createImageToFirestorageAction()
        }
    }
    
    func creatrImage(fileName: String, uploadImage: Data) {
        //Save to Firebase Storage
        let storageRef = Storage.storage().reference().child("profile_image").child(fileName)
        storageRef.putData(uploadImage, metadata: nil) { (metadate, err) in
            if let err = err {
                print("Failed to save to Firestorage.\(err)")
                //Processing when registration of user information fails
                return
            }
            print("Successfully saved to Firestorage.")
            //Completed saving to Firebase Storage->Save to Firebase Firestore
            self.delegate?.createUserToFirestoreAction(fileName: fileName)
        }
    }
    
    func createUserInfo(uid: String, docDate: [String : Any]) {
        //Save to Firebase Firestore
        Firestore.firestore().collection("users").document(uid).setData(docDate as [String : Any]) { (err) in
            if let err = err {
                print("Failed to save to Firestore.\(err)")
                //Processing when registration of user information fails
                return
            }
            print("You have successfully saved to the Firestore.")
            //Processing when registration of user information is completed
            self.delegate?.completedRegisterUserInfoAction()
        }
    }

}

SignUpViewController.swift


import UIKit
import Firebase
import FirebaseStorage
import IQKeyboardManagerSwift

class SignUpViewController: UIViewController {
    
    @IBOutlet weak var profileImageButton: UIButton!
    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var userNameTextField: UITextField!
    @IBOutlet weak var signUpButton: UIButton!
    
    let signUpModel = SignUpModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        IQKeyboardManager.shared.enable = true
        
        emailTextField.delegate = self
        passwordTextField.delegate = self
        userNameTextField.delegate = self
        signUpModel.delegate = self
        
        //Processing about screen UI
        setupUI()
        
    }
    
    //Processing about screen UI
    func setupUI() {
        signUpButton.layer.cornerRadius = 3
        signUpButton.isEnabled = false
        profileImageButton.layer.masksToBounds = true
        profileImageButton.layer.cornerRadius = 75
        profileImageButton.layer.borderColor = UIColor.lightGray.cgColor
        profileImageButton.layer.borderWidth  = 0.1
    }
    
    //Select profile image (transition to photo library)
    @IBAction func profileImageButtonAction(_ sender: Any) {
        let imagePickerController = UIImagePickerController()
        imagePickerController.allowsEditing = true
        imagePickerController.delegate = self
        self.present(imagePickerController, animated: true, completion: nil)
    }
    
    //New registration process
    @IBAction func signUpButtonAction(_ sender: Any) {
        
        guard let email = emailTextField.text,
              let password = passwordTextField.text
        else { return }
        
        //Save to Firebase Auth
        signUpModel.createUser(email: email, password: password)      
    }
    
    #···abridgement···
    
    //Processing to save profile image to Firebase Storage
    private func createImageToFirestorage() {
        //Processing when profile image is set
        if let image = self.profileImageButton.imageView?.image {
            let uploadImage = image.jpegData(compressionQuality: 0.5)
            let fileName = NSUUID().uuidString
            //Save to Firebase Storage
            signUpModel.creatrImage(fileName: fileName, uploadImage: uploadImage!) 
        } else {
            print("Since the profile image is not set, it will be the default image.")
            //Save User information to Firebase Firestore
            self.createUserToFirestore(profileImageName: nil)
        } 
    }
    
    //Process to save User information in Firebase Firestore
    private func createUserToFirestore(profileImageName: String?) {
        
        guard let email = Auth.auth().currentUser?.email,
              let uid = Auth.auth().currentUser?.uid,
              let userName = self.userNameTextField.text
        else { return }
        
        //Define saved contents (dictionary type)
        let docData = ["email": email,
                       "userName": userName,
                       "profileImageName": profileImageName,
                       "createdAt": Timestamp()] as [String : Any?]
        
        //Save to Firebase Firestore
        signUpModel.createUserInfo(uid: uid, docDate: docData as [String : Any])
    }
    
}

extension SignUpViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
    //Method called when a photo is selected
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let editedImage = info[.editedImage] as? UIImage {
            profileImageButton.setImage(editedImage.withRenderingMode(.alwaysOriginal), for: .normal)
        } else if let originalImage = info[.originalImage] as? UIImage {
            profileImageButton.setImage(originalImage.withRenderingMode(.alwaysOriginal), for: .normal)
        }
        dismiss(animated: true, completion: nil)
    }
    
}

extension SignUpViewController: UITextFieldDelegate {
    //Method called when the text selection is changed in textField
    func textFieldDidChangeSelection(_ textField: UITextField) {
        //Variable to determine if textField is empty(Bool type)Defined in
        let emailIsEmpty = emailTextField.text?.isEmpty ?? true
        let passwordIsEmpty = passwordTextField.text?.isEmpty ?? true
        let userNameIsEmpty = userNameTextField.text?.isEmpty ?? true
        //Processing when all textFields have been filled in
        if emailIsEmpty || passwordIsEmpty || userNameIsEmpty {
            signUpButton.isEnabled = false
            signUpButton.backgroundColor = UIColor.systemGray2
        } else {
            signUpButton.isEnabled = true
            signUpButton.backgroundColor = UIColor(named: "lineGreen")
        }
    }
    
    //Keyboard closes when you press anything other than textField
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }
}

extension SignUpViewController: SignUpModelDelegate {
            
    //Completed saving to Firebase Auth->Save to Firebase Storage
    func createImageToFirestorageAction() {
        print("Successfully saved to Firebase Auth.")
        self.createImageToFirestorage()
    }
    
    //Completed saving to Firebase Storage->Save to Firebase Firestore
    func createUserToFirestoreAction(fileName: String?) {
        print("Successfully saved to Firestorage.")
        self.createUserToFirestore(profileImageName: fileName)
    }
    
    //Processing when registration of user information is completed
    func completedRegisterUserInfoAction() {
        //Screen transition to ChatListViewController
        let storyboard = UIStoryboard(name: "ChatList", bundle: nil)
        let chatListVC = storyboard.instantiateViewController(withIdentifier: "ChatListVC") as! ChatListViewController
        let nav = UINavigationController(rootViewController: chatListVC)
        nav.modalPresentationStyle = .fullScreen
        nav.modalTransitionStyle = .crossDissolve
        self.present(nav, animated: true, completion: nil)
    }
    
}

Since we are focusing on the processing related to Firebase, we will omit the explanation of the following items.

--About error handling --About ʻUIActivityIndicatorView --About ʻUIImagePickerController --About ʻIQKeyboardManagerSwift` (For details, please refer to here.)

Preparation

① Prerequisites

We will proceed on the premise that the following items have been completed.

--Creating a Firebase project --Built-in Firebase SDK in Xcode

If you haven't heard about this yet, please refer to Documentation.

② Preparation on the Xcode side

Add the following to the Podfile and do pod install in the terminal.

  pod 'Firebase/Analytics'
  pod 'Firebase/Auth'
  pod 'Firebase/Core'
  pod 'Firebase/Firestore'
  pod 'Firebase/Storage'
  pod 'FirebaseUI/Storage'

③ Preparation on the Firebase side

スクリーンショット 2020-10-12 20.15.13.png Select Mail / Password from the Sign-in method tab as shown above. Open the edit screen with the pencil icon.

スクリーンショット 2020-10-12 20.15.21.png Save it once enabled. This is the end of the preparation.

Implementation details ① (Firebase Auth edition)

SignUpViewController.swift


//New registration process
@IBAction func signUpButtonAction(_ sender: Any) {
        
    guard let email = emailTextField.text,
          let password = passwordTextField.text
    else { return }
        
    //Save to Firebase Auth
    signUpModel.createUser(email: email, password: password)      
}

SignUpModel.swift


func createUser(email: String, password: String) {
    //Save to Firebase Auth
    Auth.auth().createUser(withEmail: email, password: password) { (res, err) in
        if let err = err {
            print("Failed to save to Firebase Auth.\(err)")
            //Processing when registration of user information fails
            return
        }
        print("Successfully saved to Firebase Auth.")
        //Completed saving to Firebase Auth->Save to Firebase Storage
        self.delegate?.createImageToFirestorageAction()
    }
}

Implementation details ② (Firebase Storage)

SignUpViewController.swift


//Completed saving to Firebase Auth->Save to Firebase Storage
func createImageToFirestorageAction() {
    print("Successfully saved to Firebase Auth.")
    self.createImageToFirestorage()
}

SignUpViewController.swift


//Processing to save profile image to Firebase Storage
private func createImageToFirestorage() {
    //Processing when profile image is set
    if let image = self.profileImageButton.imageView?.image {
        //Compress image
        let uploadImage = image.jpegData(compressionQuality: 0.5)
        //Get a unique ID
        let fileName = NSUUID().uuidString
        //Save to Firebase Storage
        signUpModel.creatrImage(fileName: fileName, uploadImage: uploadImage!) 
    } else {
        print("Since the profile image is not set, it will be the default image.")
        //Save User information to Firebase Firestore
        self.createUserToFirestore(profileImageName: nil)
    } 
}

SignUpModel.swift


func creatrImage(fileName: String, uploadImage: Data) {
    //Save to Firebase Storage
    let storageRef = Storage.storage().reference().child("profile_image").child(fileName)
    storageRef.putData(uploadImage, metadata: nil) { (metadate, err) in
        if let err = err {
            print("Failed to save to Firestorage.\(err)")
            //Processing when registration of user information fails
            return
        }
        print("Successfully saved to Firestorage.")
        //Completed saving to Firebase Storage->Save to Firebase Firestore
        self.delegate?.createUserToFirestoreAction(fileName: fileName)
    }
}

Implementation details ③ (Firebase Firestore edition)

SignUpViewController.swift


//Completed saving to Firebase Storage->Save to Firebase Firestore
func createUserToFirestoreAction(fileName: String?) {
    print("Successfully saved to Firestorage.")
    self.createUserToFirestore(profileImageName: fileName)
}

SignUpViewController.swift


//Process to save User information in Firebase Firestore
private func createUserToFirestore(profileImageName: String?) {
        
    guard let email = Auth.auth().currentUser?.email,
          let uid = Auth.auth().currentUser?.uid,
          let userName = self.userNameTextField.text
    else { return }
        
    //Define saved contents (dictionary type)
    let docData = ["email": email,
                   "userName": userName,
                   "profileImageName": profileImageName,
                   "createdAt": Timestamp()] as [String : Any?]
        
    //Save to Firebase Firestore
    signUpModel.createUserInfo(uid: uid, docDate: docData as [String : Any])
}

SignUpModel.swift


func createUserInfo(uid: String, docDate: [String : Any]) {
    //Save to Firebase Firestore
    Firestore.firestore().collection("users").document(uid).setData(docDate as [String : Any]) { (err) in
        if let err = err {
            print("Failed to save to Firestore.\(err)")
            //Processing when registration of user information fails
            return
        }
        print("You have successfully saved to the Firestore.")
        //Processing when registration of user information is completed
        self.delegate?.completedRegisterUserInfoAction()
    }
}

SignUpViewController.swift


//Processing when registration of user information is completed
func completedRegisterUserInfoAction() {
    //Screen transition to ChatListViewController
    #···abridgement···
}

reference

-[Swift] LINE-style Chat app creation (Ep1) --Explanation of overview and creation of ChatList screen -[Firebase] [iOS] Let's create a membership function with Firebase Authentication -[IOS] How to save / retrieve images to Firebase Storage

Recommended Posts

[Swift 5] Implementation of membership registration with Firebase
[Swift] Simple implementation of UIImageView
[Swift] Implementation of ultra-simple billing
Implementation of XLPagerTabStrip with TabBarController
How to get the ID of a user authenticated with Firebase in Swift
SKStoreReviewController implementation memo in Swift UI of iOS14
[Swift] How to link the app with Firebase
[Swift] First Firebase
Implementation of GKAccessPoint
[Swift] Get the number of steps with CMP edometer
[Swift] This is the solution! Illustration of Delegate implementation
[Swift] How to get the document ID of Firebase
Display 3D objects of SceneKit with Swift UI, etc.
Implementation of flash messages
Implementation of search function
Applied implementation of chat-space
Getting Started with Swift
Implementation of pagination function
Registration of multiple WebMvcConfigurers
Starting with Swift Swift UI
Pagination implementation with gem'kaminari'
[Swift] You can concatenate cells with Drag & Drop of UITableView
[Java] Simplify the implementation of data history management with Reladomo
Implementation of a math parser with recursive descent parsing (Java)