포스트

TikTok Clone (3)

Textfield 유효 함수 구현

여러 Textfield 값이 입력이 될때 해당 컴포넌트에 제대로 값이 있는지 확인하는 함수를 구현한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func validateFields() {
        guard let username = self.usernameTextfield.text, !username.isEmpty else {
            print("Please enter an username")
            return
        }
        guard let email = self.emailTextfield.text, !email.isEmpty else {
            print("Please enter an username")
            return
        }
        guard let password = self.passwordTextfield.text, !password.isEmpty else {
            print("Please enter an username")
            return
        }
    }

우선은 틀만 이렇게 잡는다.

그리고 버튼을 클릭했을때 작동이 먼저되게

1
2
@IBAction func signUpDidTapped(_ sender: Any) {
        self.validateFields()

여기에 바로 구현.

버튼을 클릭하니

1
2
Please enter an username
Avatar is nil

이렇게 나온다.

Progress HUD 사용.

주소는 여기에

SPM으로 추가한다.

이전에는 showError 메서드가 있었으나 지금은 없다. 그래서 failed로 대체

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func validateFields() {
        guard let username = self.usernameTextfield.text, !username.isEmpty else {
            ProgressHUD.failed("Please enter an username")
            return
        }
        guard let email = self.emailTextfield.text, !email.isEmpty else {
            ProgressHUD.failed("Please enter a email")
            return
        }
        guard let password = self.passwordTextfield.text, !password.isEmpty else {
            ProgressHUD.failed("Please enter a password")
            return
        }
    }

May-19-2024 23-15-08

실행하니 아주 괜찮다.

이미지에도 적용을 해주자.

1
2
3
4
guard let imageSelected = self.image else {
            ProgressHUD.failed("Please enter a Profile Image")
            return
        }

textfield값 적용

이전까지는 이메일주소, 비밀번호를 미리 파라미터에 입력했다면 이젠 textfield의 값을 받도록 변경한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@IBAction func signUpDidTapped(_ sender: Any) {
        self.validateFields()
        
        
        guard let imageSelected = self.image else {
            ProgressHUD.failed("Please enter a Profile Image") // modified
            return
        }
        guard let imageData = imageSelected.jpegData(compressionQuality: 0.4) else {return}
        
        Auth.auth().createUser(withEmail: self.emailTextfield.text!, password: self.passwordTextfield.text!) { authDataResut, error in // modified
            if error != nil {
                print(error!.localizedDescription)
                return
            }
            if let authData = authDataResut {
                print(authData.user.email)
                var dict: Dictionary<String, Any> = [
                    "uid": authData.user.uid,
                    "email": authData.user.email,
                    "username": self.usernameTextfield.text!, // added
                    "profileImageUrl": "",
                    "status": ""
                ]

DB를 리셋시키고 테스트를 해보자.

그전에 비밀번호를 보이지 않게 하기위해

CleanShot 2024-05-19 at 23 21 06@2x

여기 부분을 체크해주자.

May-19-2024 23-23-31

아직 이후 액션이 없어서 저기서 멍때리지만

DB에는 값이 잘 들어온걸로 확인이 된다.

사진은 pass

그리고 extension을 통해 signUp이라는 함수로 코드를 옮겨준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
extension SignUpViewController {
    
    func signUp() {
        guard let imageSelected = self.image else {
            ProgressHUD.failed("Please enter a Profile Image")
            return
        }
        guard let imageData = imageSelected.jpegData(compressionQuality: 0.4) else {return}
        
        Auth.auth().createUser(withEmail: self.emailTextfield.text!, password: self.passwordTextfield.text!) { authDataResut, error in
            if error != nil {
                print(error!.localizedDescription)
                return
            }
            if let authData = authDataResut {
                print(authData.user.email)
                var dict: Dictionary<String, Any> = [
                    "uid": authData.user.uid,
                    "email": authData.user.email,
                    "username": self.usernameTextfield.text!,
                    "profileImageUrl": "",
                    "status": ""
                ]
                let storageRef = Storage.storage().reference(forURL: "gs://tiktoktutorial-d9129.appspot.com")
                let storageProfileRef = storageRef.child("profile").child(authData.user.uid)
                let metaData = StorageMetadata()
                metaData.contentType = "image/jpg"
                storageProfileRef.putData(imageData, metadata: metaData) { storageMetaData, error in
                    if error != nil {
                        print(error!.localizedDescription)
                        return
                    }
                    storageProfileRef.downloadURL { url, error in
                        if let metaImageUrl = url?.absoluteString {
                            print(metaImageUrl)
                            dict["profileImageUrl"] = metaImageUrl
                            Database.database().reference().child("users").child(authData.user.uid).updateChildValues(dict) { error, ref in
                                if error != nil {
                                    print("Done")
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    
}

그리고 원래 objc 함수에는

1
2
3
4
@IBAction func signUpDidTapped(_ sender: Any) {
        self.validateFields()
        self.signUp()
    }

이렇게 단순하게 해준다.

Api 구현

정확하게는 위에 정리한 함수를 클래스처럼해서 모듈화 해주는것이다.

1
2
3
struct Api {
    static var User = UserApi()
}

이렇게 만들고

UserApi 부분에

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import UIKit
import FirebaseAuth
import FirebaseStorage
import FirebaseDatabase
import ProgressHUD

class UserApi {
    func signUp (withUsername username: String, email: String, password: String, image: UIImage?, onSuccess: @escaping() -> Void, onError: @escaping (_ errorMessage: String) -> Void) {
        guard let imageSelected = image else {
            ProgressHUD.failed("Please enter a Profile Image")
            return
        }
        guard let imageData = imageSelected.jpegData(compressionQuality: 0.4) else {return}
        
        Auth.auth().createUser(withEmail: email, password: password) { authDataResult, error in
            if error != nil {
                print(error!.localizedDescription)
                return
            }
            if let authData = authDataResult {
                print(authData.user.email)
                var dict: Dictionary<String, Any> = [
                    "uid": authData.user.uid,
                    "email": authData.user.email,
                    "username": username,
                    "profileImageUrl": "",
                    "status": ""
                ]
                let storageRef = Storage.storage().reference(forURL: "gs://tiktoktutorial-d9129.appspot.com")
                let storageProfileRef = storageRef.child("profile").child(authData.user.uid)
                let metaData = StorageMetadata()
                metaData.contentType = "image/jpg"
                storageProfileRef.putData(imageData, metadata: metaData) { storageMetaData, error in
                    if error != nil {
                        print(error!.localizedDescription)
                        return
                    }
                    storageProfileRef.downloadURL { url, error in
                        if let metaImageUrl = url?.absoluteString {
                            print(metaImageUrl)
                            dict["profileImageUrl"] = metaImageUrl
                            Database.database().reference().child("users").child(authData.user.uid).updateChildValues(dict) { error, ref in
                                if error == nil {
                                    onSuccess()
                                } else {
                                    onError(error!.localizedDescription)
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

이 내용을 모두 옮겼다.

특이점이라면 CompletionHandler를 사용하였고, success와 failure를 나눠서 구현했다.

VC로 돌아와서는

1
2
3
4
5
6
7
8
func signUp() {
        Api.User.signUp(withUsername: self.usernameTextfield.text!, email: self.emailTextfield.text!, password: self.passwordTextfield.text!, image: self.image) {
            print("Done")
        } onError: { errorMessage in
            print(errorMessage)
        }

    }

이렇게 심플하게 처리해주면 끝.

실행해서 확인

작동이 된다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.