포스트

Final (17)

Custom 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
25
26
27
28
29
30
31
32
33
34
35
36
class CustomTextField: UITextField {
    
    init(placeholder: String, keyboardType: UIKeyboardType = .default, target: Any?, action: Selector) {
        super.init(frame: .zero)
        self.placeholder = placeholder
        leftViewMode = .always
        borderStyle = .none
        textColor = .black
        keyboardAppearance = .light
        clearButtonMode = .whileEditing
        autocorrectionType = .no
        spellCheckingType = .no
        
        self.keyboardType = keyboardType
        
        let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIView().frame.size.width, height: 36))
        toolBar.barStyle = .default
        toolBar.sizeToFit()
        let doneButton = UIBarButtonItem(
            title: "Done",
            style: .plain,
            target: target,
            action: action)
        toolBar.items = [
            UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),
            doneButton
        ]
        
        toolBar.isUserInteractionEnabled = true
        inputAccessoryView = toolBar
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

이렇게 해서 이전에는 func로 했다면 이번엔 애초에 클래스를 하나 만들었다.

완료.

처음에 유져 인증시 검은 화면 나오는 부분 수정

SceneDelegate에서

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
            guard let windowScene = (scene as? UIWindowScene) else { return }
            
            let window = UIWindow(windowScene: windowScene)
            self.window = window
            
            let loadingVC = UIViewController()
            loadingVC.view.backgroundColor = .white 
            let activityIndicator = UIActivityIndicatorView(style: .large)
            activityIndicator.center = loadingVC.view.center
            activityIndicator.startAnimating()
            loadingVC.view.addSubview(activityIndicator)
            
            window.rootViewController = loadingVC
            window.makeKeyAndVisible()
            
            configureInitialViewController()
        }

configureInitialViewController() 이 실행이 될때 그 찰나의 순간에 검은 화면으로 보이는 경우가 있다.

이부분을 조금 더 바꿔주기 위해서 위와같이 VC를 하나 만들고 indicator를 띄우는 방식으로 했다.

Jun-16-2024 10-56-21

Completion 문제 해결

현재가 문제가 되는 부분

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private func bind() {
        viewModel.loginPublisher.sink { [weak self] completion in
            switch completion {
            case .finished:
                return
            case .failure(let error):
                self?.showMessage(title: "에러 발생", message: "\(error.localizedDescription)발생했습니다.")
            }
        } receiveValue: { _ in
            let scene = UIApplication.shared.connectedScenes.first
            if let sd: SceneDelegate = (scene?.delegate as? SceneDelegate) {
                sd.switchToMainTabBarController()
            }
        }.store(in: &cancellables)
    }

completion 부분에서 finished or failure가 한번 발생하게 되면 이후에 다시 재작동을 안하게 된다.

우선 publisher를 변경한다.

1
2
3
4
5
// before
var loginPublisher = PassthroughSubject<Void, Error>()

// after
var loginPublisher = PassthroughSubject<Result<Void, Error>, Never>()

우선 PassthroughSubject의 속성을 알아야 한다.

CleanShot 2024-06-16 at 17 00 19@2x

output과 failure로 전달을 하게 되는데

나는 여기서 Failure에 Error를 전달을 했던 것.

그러다보니 sinke에 자연스럽게 completion이 생겼던 것이고, 한번 completion이 발생하고나선 이후에 해당 부분이 skip이 되는 상황이 발생 했던 것.

그래서 Failure에 Never를 전달하고, output에 result를 사용하여 void, Error로 기존처럼 전달을하게 했다.

그래서 자연스럽게 bind 부분도 달라졌다.

CleanShot 2024-06-16 at 20 21 39@2x

CleanShot 2024-06-16 at 20 22 16@2x

이렇게 같은 sink라도 completion이 있고 없고 다르다.

이렇게 바꿔 줌으로써 문제 해결.

1
2
3
4
5
6
7
8
9
10
11
12
13
private func bind() {
        viewModel.loginPublisher.sink { [weak self] result in
            switch result {
            case .success():
                let scene = UIApplication.shared.connectedScenes.first
                if let sd: SceneDelegate = (scene?.delegate as? SceneDelegate) {
                    sd.switchToMainTabBarController()
                }
            case .failure(let error):
                self?.showMessage(title: "에러 발생", message: "\(error.localizedDescription)발생했습니다.")
            }
        }.store(in: &cancellables)
    }

위와 차이점은 성공 결과에 따라 전달은 되나 completion이 아니기에 subscription이 유지 된다라는 가장 큰 차이점이 존재.

계정 생성시 realtimeDatabase에 추가 안되던 문제 수정

팀원분의 제보로 계정을 새로 만들면 무한로딩이 발생한다는것을 알게 되었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func googleLoginDidTapped(presentViewController: UIViewController) {

    // 중략
                    
                    if let snapshot = snapshot {
                        let userData = snapshot.value as! [String: Any]
                        let isBlockInt = userData[db_isBlock] as? Int ?? 0
                        let isBlock = isBlockInt != 0
                        if isBlock {
                            let error = NSError(domain: "", code: 403, userInfo: [NSLocalizedDescriptionKey: "현재 계정은 계정차단 관련 문제가 "])
                            self?.loginPublisher.send(completion: .failure(error))
                            self?.signOut()
                        } else {
                            self?.loginPublisher.send(())
                        }
                    } else {
                        let model = UserModel(uid: user.uid, email: email!, isBlock: false, nickName: "", profileImageUrl: "https://firebasestorage.googleapis.com/v0/b/tteoppokki4u.appspot.com/o/dummyProfile%2FdefaultImage.png?alt=media&token=b4aab21e-e19a-42b7-9d17-d92a3801a327")
                        self?.signManager.saveUserData(user: model)
                        self?.loginPublisher.send(())
                    }
                }
            }
        }
    }

여기서 옵셔널 바인딩하면서 당연히 예외로 새로 생성을 한다고 생각했던게 잘못 되었다.

그래서 snapshot의 존재유무로 확인하려 했으나 바로 exception 발생

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
func googleLoginDidTapped(presentViewController: UIViewController) {

    // 중략                    
                    if let snapshot = snapshot {
                        if snapshot.exists() {
                            let userData = snapshot.value as! [String: Any]
                            let isBlockInt = userData[db_isBlock] as? Int ?? 0
                            let isBlock = isBlockInt != 0
                            if isBlock {
                                let error = NSError(domain: "", code: 403, userInfo: [NSLocalizedDescriptionKey: "현재 계정은 계정차단 관련 문제가 "])
                                self?.loginPublisher.send( .failure(error))
                                self?.signOut()
                            } else {
                                self?.loginPublisher.send(.success(()))
                            }
                        } else {
                            let model = UserModel(uid: user.uid, email: email!, isBlock: false, nickName: "", profileImageUrl: "https://firebasestorage.googleapis.com/v0/b/tteoppokki4u.appspot.com/o/dummyProfile%2FdefaultImage.png?alt=media&token=b4aab21e-e19a-42b7-9d17-d92a3801a327")
                            self?.signManager.saveUserData(user: model)
                            self?.loginPublisher.send(.success(()))
                        }
                        
                    }
                }
            }
        }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func googleLoginDidTapped(presentViewController: UIViewController) {

                    
                    if let snapshot = snapshot {
                        if let userData = snapshot.value as? [String: Any] {
                            let isBlockInt = userData[db_isBlock] as? Int ?? 0
                            let isBlock = isBlockInt != 0
                            if isBlock {
                                let error = NSError(domain: "", code: 403, userInfo: [NSLocalizedDescriptionKey: "현재 계정은 계정차단 관련 문제가 "])
                                self?.loginPublisher.send(.failure(error))
                                self?.signOut()
                            } else {
                                self?.loginPublisher.send(.success(()))
                            }
                        } else {
                            let model = UserModel(uid: user.uid, email: email!, isBlock: false, nickName: "", profileImageUrl: "https://firebasestorage.googleapis.com/v0/b/tteoppokki4u.appspot.com/o/dummyProfile%2FdefaultImage.png?alt=media&token=b4aab21e-e19a-42b7-9d17-d92a3801a327")
                            self?.signManager.saveUserData(user: model)
                            self?.loginPublisher.send(.success(()))
                        }
                    }
                }
            }
        }
    }

userdata가 존재한다면 즉 document안에 값이 있다면으로 if문을 조금더 구체화 시켜주었다.

문제 해결 완료.

Jun-16-2024 17-38-34

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