deprecated/꼼꼼한 재은씨 시리즈

프로필 화면 구현 - 코드 리뷰

lgvv 2021. 3. 28. 16:42

목적 : 넘 다양한 스킬이 나오는데 하나의 흐름으로 쭉 끌고가다 보니 한번 정리를 할 필요성을 느낌

여기 코드는 구현한 프로필 화면에 대해서 코드를 다시 보고 지나감.

 

커스텀 테이블 뷰 구성하는 부분 꼭 보기

테이블 뷰 설정시 메인 스토리보드에서 네비게이션 컨트롤러로 구현되었기 때문에 테이블 뷰도 테이블뷰 딜게랑 데소 연결해서 커스텀하게 구성해줘야한다. 테이블 뷰 구성하는 코드 꼭 보기

 

또한 이게 중요한 이유는 배치를 잘못하면 다르게 그림 나오고 클릭도 안되고 골아픈게 많음 .

 

웹 css 처럼 배치하는 느낌인데 이게 엄청 복잡해지면 어려울 것 같으나 여튼 잘 해결했음

여기 코드 쭉 읽어보면서 이해하길 바람~!

//
//  ProfileVC.swift
//  MyMemory
//
//  Created by prologue on 2017. 6. 9..
//  Copyright © 2017년 rubypaper. All rights reserved.
//

import UIKit
class ProfileVC: UIViewController, UITableViewDelegate, UITableViewDataSource, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    /*
        테이블 뷰는 사용하지만 테이블 뷰 컨트롤러는 아니다.
        따라서 테이블 뷰를 위한 프로토콜을 직접 추가해줘야한다.
        UITableViewDelegate는 테이블 뷰에서 발생하는 사용자 액션에 응답하기 위한 프로토콜이며
        UITableViewDataSource는 테이터 소스를 이용하여 테이블 뷰를 구성하기 위해 필요한 프로토콜이다.
        또한 필수 구현 메소드가 포함되어 있기 때문에 이를 구현하지 않으면 컴파일러의 오류가 발생한다.
        */
    
  let uinfo = UserInfoManager() // 개인정보 관리 매니저
  let profileImage = UIImageView() // 프로필 사진 이미지
  let tv = UITableView() // 프로필 목록
  
  override func viewDidLoad() {
    self.navigationItem.title = "프로필"
    
    // 뒤로 가기 버튼 처리
    let backBtn = UIBarButtonItem(title: "닫기", style: .plain, target: self, action: #selector( close(_:) ))
    self.navigationItem.leftBarButtonItem = backBtn
    
    // 추가되는 부분) 배경 이미지 설정
    let bg = UIImage(named: "profile-bg")
    let bgImg = UIImageView(image: bg)
    bgImg.frame.size = CGSize(width: bgImg.frame.size.width, height: bgImg.frame.size.height)
    bgImg.center = CGPoint(x: self.view.frame.width / 2, y: 40)
    bgImg.layer.cornerRadius = bgImg.frame.size.width / 2
    bgImg.layer.borderWidth = 0
    bgImg.layer.masksToBounds = true
    
    self.view.addSubview(bgImg)
    
    self.view.bringSubviewToFront(self.tv)
    self.view.bringSubviewToFront(self.profileImage)
    
    // ① 프로필 사진에 들어갈 기본 이미지
    //let image = UIImage(named: "account.jpg")
    let image = self.uinfo.profile
    
    // ② 프로필 이미지 처리
    self.profileImage.image = image
    self.profileImage.frame.size = CGSize(width: 100, height: 100)
    self.profileImage.center = CGPoint(x: self.view.frame.width / 2, y: 270)
    
    // ③ 프로필 이미지 둥글게 만들기
    self.profileImage.layer.cornerRadius = self.profileImage.frame.width / 2
    self.profileImage.layer.borderWidth = 0
    self.profileImage.layer.masksToBounds = true
    
    // ④ 루트 뷰에 추가
    self.view.addSubview(self.profileImage)
    
    // 테이블 뷰
    self.tv.frame = CGRect(x: 0,
                           y: self.profileImage.frame.origin.y + self.profileImage.frame.size.height + 20,
                           width: self.view.frame.width,
                           height: 100)
    self.tv.dataSource = self
    self.tv.delegate = self
    self.view.addSubview(self.tv)
    
    // 내비게이션 바 숨김 처리
    self.navigationController?.navigationBar.isHidden = true
    
    self.drawBtn()
    
    
    // 프로필 이미지 뷰 객체에 탭 제스처를 등록하고 이를 profile(_:)과 연결합니다.
    let tap = UITapGestureRecognizer(target: self, action: #selector(profile(_:)))
    self.profileImage.addGestureRecognizer(tap)
    self.profileImage.isUserInteractionEnabled = true
  }
  
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 2
  }
  
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell(style: .value1, reuseIdentifier: "cell")
    
    cell.textLabel?.font = UIFont.systemFont(ofSize: 14)
    cell.detailTextLabel?.font = UIFont.systemFont(ofSize: 13)
    cell.accessoryType = .disclosureIndicator
    
    switch indexPath.row {
      case 0 :
        cell.textLabel?.text = "이름"
        //cell.detailTextLabel?.text = "lgvv9898"
        cell.detailTextLabel?.text = self.uinfo.name ?? "Login Please"
      case 1 :
        cell.textLabel?.text = "계정"
        //cell.detailTextLabel?.text = "lgvv9898.tistory"
        cell.detailTextLabel?.text = self.uinfo.account ?? "Login Please"
      default :
        ()
    }
    return cell
  }
  
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if self.uinfo.isLogin == false { // 로그인이 되어 있지 않다면 창의 띄워준다.
            self.doLogin(self.tv)
        }
    }
    
  @objc func close(_ sender: Any) {
    self.presentingViewController?.dismiss(animated: true)
  }
    
    @objc func doLogin(_ sender : Any){
        let loginAlert = UIAlertController(title: "LOGIN", message: nil, preferredStyle: .alert)
        
        loginAlert.addTextField { (tf) in
            tf.placeholder = "Your Account"
        }
        
        loginAlert.addTextField { (tf) in
            tf.placeholder = "Password"
            tf.isSecureTextEntry = true
        }
        
        loginAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        loginAlert.addAction(UIAlertAction(title: "Login", style: .destructive, handler: { (_) in
            let account = loginAlert.textFields?[0].text ?? "" // 문법 중 하나인데 트푸면 앞에 거짓이면 뒤에
            let passwd = loginAlert.textFields?[1].text ?? ""
            
            if self.uinfo.login(account: account, passwd: passwd){
                self.tv.reloadData() // 테이블 뷰를 갱신한다
                self.profileImage.image = self.uinfo.profile // 이미지 프로필을 갱신한다.
                self.drawBtn() // 로그인 상태에 따라 적절히 로그인/로그아웃 버튼을 출력한다.
            } else {
                let msg = "로그인에 실패함"
                let alert = UIAlertController(title: nil, message: msg, preferredStyle: .alert)
                
                alert.addAction(UIAlertAction(title: "ok", style: .cancel, handler: nil))
            
            }
            
        }))
        self.present(loginAlert, animated: false, completion: nil)
        
    }
    
    @objc func doLogout(_ sender : Any) {
        let msg = "로그아웃 하시겠습니까?"
        let alert = UIAlertController(title: nil, message: msg, preferredStyle: .alert)
        
        alert.addAction(UIAlertAction(title: "취소", style: .cancel, handler: nil))
        alert.addAction(UIAlertAction(title: "확인", style: .destructive, handler: { (_) in
            if self.uinfo.logout() {
                self.tv.reloadData() // 테이블 뷰를 갱신한다
                self.profileImage.image = self.uinfo.profile // 이미지 프로필을 갱신한다.
                self.drawBtn() // 로그인 상태에 따라 적절히 로그인/로그아웃 버튼을 출력한다.
            }
        }))
        
        self.present(alert, animated: false, completion: nil)
    }
    
    func drawBtn() {
        // 버튼을 감쌀 뷰를 정의한다.
        let v = UIView()
        v.frame.size.width = self.view.frame.width
        v.frame.size.height = 40
        v.frame.origin.x = 0
        v.frame.origin.y = self.tv.frame.origin.y + self.tv.frame.height
        v.backgroundColor = UIColor(red:0.98, green:0.98, blue:0.98, alpha:1.0)
        
        self.view.addSubview(v)
        
        // 버튼을 정의한다.
        let btn = UIButton(type: .system)
        btn.frame.size.width = 100
        btn.frame.size.height = 30
        btn.center.x = v.frame.size.width / 2
        btn.center.y = v.frame.size.height / 2
        
        // 로그인 상태일 때는 로그아웃 버튼을, 로그아웃 상태일 때에는 로그인 버튼을 만들어 준다.
        if self.uinfo.isLogin == true {
          btn.setTitle("로그아웃", for: .normal)
          btn.addTarget(self, action: #selector(doLogout(_:)), for: .touchUpInside)
        } else {
          btn.setTitle("로그인", for: .normal)
          btn.addTarget(self, action: #selector(doLogin(_:)), for: .touchUpInside)
        }
        v.addSubview(btn)
    }
    
    func imgPicker( _ source : UIImagePickerController.SourceType) {
        let picker = UIImagePickerController()
        picker.sourceType = source
        picker.delegate = self
        picker.allowsEditing = true
        self.present(picker, animated: true, completion: nil)
    }
    
    @objc func profile(_ sender : UIButton) { // 프ㅗ필 사진의 소스 타입을 선택하는 메소드
        guard self.uinfo.account != nil else { // 로그인이 되어 있지 않은 경우는 프로필 이미지 등록을 막고 대신 로그인 창을 띄워준다.
            self.doLogin(self)
            return
        }
        
        let alert = UIAlertController(title: nil, message: "사진을 가져올 곳을 선택해 주세요", preferredStyle: .actionSheet)
        
        if UIImagePickerController.isSourceTypeAvailable(.camera) {
            alert.addAction(UIAlertAction(title: "camera", style: .default){ (_) in
                self.imgPicker(.camera)
            })
        }
        
        if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum) {
            alert.addAction(UIAlertAction(title: "saved albums", style: .default){ (_) in
                self.imgPicker(.savedPhotosAlbum)
            })
        }
        
        if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
            alert.addAction(UIAlertAction(title: "photo library", style: .default){ (_) in
                self.imgPicker(.photoLibrary)
            })
        }
        
        alert.addAction(UIAlertAction(title: "취소", style: .cancel, handler: nil))
        
        self.present(alert, animated: true, completion: nil)
            
        
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let img = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
            self.uinfo.profile = img
            self.profileImage.image = img
        }
        
        picker.dismiss(animated: true, completion: nil)
    }
    
    
}