포스트

Final (14)

Cell 의존성 주입

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
    private lazy var setButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("차단", for: .normal)
        button.setTitleColor(.systemBlue, for: .normal)
        button.addTarget(self, action: #selector(deactivate), for: .touchUpInside)
        return button
    }()
    
    private lazy var unsetButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("해제", for: .normal)
        button.setTitleColor(.systemRed, for: .normal)
        button.addTarget(self, action: #selector(activate), for: .touchUpInside)
        return button
    }()
    
    var activateTapped: (() -> Void)?
    var deactivateTapped: (() -> Void)?

    @objc func deactivate() {
        deactivateTapped?()
        print("deactivate tapped")
    }
    
    @objc func activate() {
        activateTapped?()
        print("activate tapped")
    }

다른부분을 날리고 이렇게 했다.

하지만 현재 작동을 하지 않는다 문제를 찾아봐야할거같다.

뭔가 Layout에서 생기는 문제같다.

문제 발견…

몇시간 동안 고민했는데 결국 지피티한테 여러번 물어보면서 알게되었다.

1
2
3
contentView.addSubview(titleLabel)
contentView.addSubview(setButton)
contentView.addSubview(unsetButton)

지피티는 문제점을 처음에 내가 추가한 방식이 잘못되었다고 했다

차이점

  1. self.addSubview(view):
    • 여기서 self는 UITableViewCell을 의미
    • 이 경우, 서브뷰가 셀 자체에 추가
  2. contentView.addSubview(view):
    • contentView는 UITableViewCell의 기본 제공 속성으로, 셀의 콘텐츠를 담는 뷰.
    • 서브뷰를 contentView에 추가하면, 테이블 뷰 셀의 레이아웃과 스타일이 올바르게 적용된다.
    • 애플은 모든 서브뷰를 contentView에 추가할 것을 권장. Docs

따라서, 서브뷰를 셀에 추가할 때는 항상 contentView를 사용해야 함.

Manager 추가

1
2
3
4
5
6
7
func editSpecificUser(uid: String, values: [String: Any], completion: @escaping ((any Error)?, DatabaseReference) -> Void) {
        ref.child(db_user_users).child(uid).updateChildValues(values, withCompletionBlock: completion)
    }
    
func getSpecificReview(uid: String, storeAddress: String, title: String, completion: @escaping(QuerySnapshot?, (Error)?) -> Void) {
        reviewCollection.whereField(db_uid, isEqualTo: uid).whereField(db_storeAddress, isEqualTo: storeAddress).whereField(db_title , isEqualTo: title).getDocuments(completion: completion)
    }

이렇게 수정용으로 만들어 주었다.

ViewModel 수정.

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
56
57
58
59
60
61
62
63
64
65
66
func activateUser(uid: String, completion: @escaping ()-> Void) {
        let values = [db_isBlock: false]
        manageManager.editSpecificUser(uid: uid, values: values) { [weak self] error, reference in
            if let error = error {
                self?.managePublisher.send(completion: .failure(error))
            }
            self?.managePublisher.send(())
            completion()
        }
    }
    
func deactivateUser(uid: String, completion: @escaping ()-> Void) {
        let values = [db_isBlock: true]
        manageManager.editSpecificUser(uid: uid, values: values) { [weak self] error, reference in
            if let error = error {
                self?.managePublisher.send(completion: .failure(error))
            }
            self?.managePublisher.send(())
            completion()
        }
    }
    
    
func activateReview(uid: String, storeAddress: String, title: String, completion: @escaping () -> Void) {
        
        let data = [db_isActive: true]
        
        manageManager.getSpecificReview(uid: uid, storeAddress: storeAddress, title: title) { [weak self] querySnapshot, error in
            
            if let error = error {
                self?.managePublisher.send(completion: .failure(error))
            }
            
            if let documents = querySnapshot?.documents {
                for doc in documents {
                    let id = doc.documentID
                    reviewCollection.document(id).setData(data, merge: true)
                    self?.managePublisher.send(())
                    completion()
                }
            }
        }
    }
    
func deactivateReview(uid: String, storeAddress: String, title: String, completion: @escaping () -> Void) {
       
        let data = [db_isActive: false]
        
        manageManager.getSpecificReview(uid: uid, storeAddress: storeAddress, title: title) { [weak self] querySnapshot, error in
            
            if let error = error {
                self?.managePublisher.send(completion: .failure(error))
            }
            
            if let documents = querySnapshot?.documents {
                for doc in documents {
                    let id = doc.documentID
                    reviewCollection.document(id).setData(data, merge: true)
                    self?.managePublisher.send(())
                    completion()
                }
            }

        }
        
    }

작동 확인 완료.

이제 제대로 된 값을 입력했을때 넘어가게 구현

VM에는 할수없는것이라 VC에서 작성

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
extension GreetingViewController {
    
    func generate(completion: @escaping (Bool) -> Void) {
        let key = Secret().key
        let alert = UIAlertController(title: "관리자 전용", message: "관리자 인증용 Key를 입력하세요.", preferredStyle: .alert)
     
        alert.addTextField { textField in
            textField.placeholder = "Key"
        }

        let confirmAction = UIAlertAction(title: "확인", style: .default) { _ in
            let text = alert.textFields?.first?.text
            
            if text == key {
                completion(true)
            } else {
                completion(false)
            }
        }
        alert.addAction(confirmAction)
        
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { _ in
            completion(false)
        }
        alert.addAction(cancelAction)
        
        present(alert, animated: true)
    }
    
}

그리고 SceneDelegate를 수정한다.

1
2
3
4
5
6
7
hiddenTapped: { 
               self.greetingVC.generate(completion: { bool in
                   if bool {
                       self.greetingVC.present(self.manageVC, animated: true)
                   }
                })
            },

Simulator Screenshot - iPhone 15 Pro - 2024-06-13 at 19 53 48

simulator_screenshot_A7A8923A-668E-44F0-ACA4-32D020BDB20D

완료.

이제 key값을 입력하면 유져, 게시글을 관리할수있는 vc가 나온다.

프로필 수정 페이지 예외 처리

문제는 아래와 같이 2가지가 존재한다.

  1. 프로필 사진을 변경하지 않고 닉네임만 변경하는 경우 무한로딩이 생기는 문제
  2. 프로필 이미지만 변경할 때는 닉네임이 들어가지 않아 “” 로 변경 되는 문제

이부분에 대한 예외 처리를 하려고한다.

우선 화면 이동시 현재 프로필 정보도 같이 넘긴다.

1
2
3
4
5
case [0, 0]:
            let personalInfoVC = PersonalInfoViewController()
            personalInfoVC.gotProfileImage = currentImageUrl
            personalInfoVC.profileName = currentName // added
            navigationController?.pushViewController(personalInfoVC, animated: true)

그리고 해당 VC에서 이미지를 저장할때 nil이거나 ““일때의 예외 처리를 하도록 구현.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if userName == "" {
            userName = profileName
        }
        
if selectedImage == nil {
            KingfisherManager.shared.retrieveImage(with: URL(string: gotProfileImage!)!) { [weak self] result in
                switch result {
                case .success(let image):
                    selectedImage = image.image
                case .failure(let error):
                    self?.showMessage(title: "에러 발생", message: "\(error)가 발생했습니다")
                }
            }
        }

해결 완료.

로그인시 block인지 아닌지 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func configureInitialViewController() {
        let auth = Auth.auth().currentUser
        if auth != nil {
            signManager.fetchUserData(uid: auth!.uid) { [weak self] error, dataSnapshot in
                if let dataSnapshot = dataSnapshot {
                    if let userData = dataSnapshot.value as? [String: Any] {
                        let isBlockInt = userData[db_isBlock] as? Int ?? 0
                        let isBlock = isBlockInt != 0
                        if isBlock {
                            self?.switchToGreetingViewController()
                            self?.greetingVC.showMessage(title: "차단 알림", message: "현재 계정은 차단되었습니다.\n관리자에게 문의하세요")
                        } else {
                            self?.switchToMainTabBarController()
                        }
                        
                    }
                }
            }
            
        } else {
            switchToGreetingViewController()
        }
    }

SceneDelegate에 다음과 같이 코드를 구현

리팩토링은 내일 하는걸로…

Jun-13-2024 23-13-37

하지만 로그인을 할때는 이게 반영이 되어있지않아서 로그인쪽도 코드를 다듬어본다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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(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(())
                            }
                            
                        }

이런식으로 집어 넣어 줬다.

Jun-13-2024 23-37-56

Jun-13-2024 23-51-44

완료.

하지만 alert가 두번째부터는 안뜨는데 그건 내일 해야겠다.

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