Swift 일기장 개발 일기 3 (present/dismiss 화면 전환)

송민준·2023년 1월 2일
0

일기장 개발 일기

목록 보기
3/11

목표

이전 글에서 언급했듯이 일기를 생성하고 tableView에 표시가 되는 상황에서 수정과 삭제 기능을 넣기 위해 새로 DetailVC를 만들어서 MainVC에 연결을 해야했습니다.

문제 인식

알다시피 tableViewCell은 버튼이 아닙니다. 즉 Action을 통해 Segue로 화면 전환을 할 수가 없습니다. (ctrl키로 다른 VC로 연결하려고 해도 안됩니다..)

구글링을 통해서 해결 방법을 찾을 수 있었는데 UITapGestureRecognizer를 이용한 방법이었습니다.

그래서 UITableViewCell를 커스텀한 커스텀 셀에 UITapGestureRecognizer를 사용해보았습니다. UITapGestureRecognizer는 UIGestureRecognizer를 상속받았으며 제스쳐의 변경이 감지되면 대상 객체에 작업 메시지를 보내는 클래스입니다.

DiaryDetailViewController

import UIKit
class DiaryDetailViewController : UIViewController {
    
    @IBOutlet weak var date: UILabel!
    
    @IBOutlet weak var emotion: UILabel!
    
    @IBOutlet weak var content: UILabel!
    
    var dateText = ""
    var emotionText = ""
    var contentText = ""
    
    override func viewDidLoad() {
        super.viewDidLoad()
        date.text = dateText
        emotion.text = emotionText
        content.text = contentText
    }
    @IBAction func backBtnPushedEvent(_ sender: Any) {
        self.presentingViewController?.dismiss(animated: true)
    }
}

일단 새로운 VC를 생성했습니다.

간단하게 날짜, 기분, 내용 Text Label과 돌아가기 버튼을 만들었습니다.
viewDidLoad에서 이전 컨트롤러로부터 전달 받은 데이터를 입력시킵니다.

그리고 저는 이 VC를 나중에 인스턴스화 하기 위해서 identifier를 diaryDetailViewController으로 입력했습니다.

그리고 뒤로가기 버튼을 눌렀을 때 액션인 backBtnPushedEvent를 만들었습니다.
self.presentingViewController?.dismiss(animated: true) : presentingViewController는 이 VC를 인스턴스화하고 present 명령을 한 VC, 여기서는 MainVC가 됩니다. 그 VC에서 dismiss를 통해서 다시 mainVC로 돌아오게 합니다.

CustomTableViewCell

import UIKit

class DiaryTableViewCell: UITableViewCell{
    var mainVC: UIViewController?
    var row: String?
    @IBOutlet weak var diaryTableViewCellDate: UILabel!
    
    @IBOutlet weak var diaryTableViewCellEmotion: UILabel!
    
    @IBOutlet weak var diaryTableViewCellContent: UILabel!
    
    override func awakeFromNib() { //Instance 화 될 때
        super.awakeFromNib()
        let tapGesture = UITapGestureRecognizer(target:self, action: #selector(cellTabEvent(sender:)))
        self.addGestureRecognizer(tapGesture)
    }
    @objc func cellTapEvent(sender: UITapGestureRecognizer) {
        guard let vc = mainVC?.storyboard?.instantiateViewController(withIdentifier: "diaryDetailViewController") as? DiaryDetailViewController else {return}
   
        vc.modalTransitionStyle = .coverVertical
        vc.modalPresentationStyle = .fullScreen
        
        vc.dateText = diaryTableViewCellDate.text!
        if let emotion = diaryTableViewCellEmotion.text {
            vc.emotionText = emotion
        }
        vc.contentText = diaryTableViewCellContent.text!
        mainVC?.present(vc, animated: true)
        
    }
}

override func awakeFromNib() { 
        super.awakeFromNib()
        let tapGesture = UITapGestureRecognizer(target:self, action: #selector(cellTapEvent(sender:)))
        self.addGestureRecognizer(tapGesture)
    }
    

awakeFromNib는 이 cell이 인스턴스화 될 때 호출되는 메서드입니다.
tableView가 cell을 하나하나 인스턴스화 할 때 각 cell에서 호출된다고 보았습니다.
let tapGestureUITapGestureRecognizer(target:self, action: #selector(cellTapEvent(sender:)))

  • "target:self" : tapGesture를 인식하는 타깃을 이 tableViewCell로 설정합니다.
  • "action:#selector(cellTapEvent(sender:))" : 인식이 되었을 때 cellTapEvent 작업을 시작합니다.

@objc func cellTapEvent(sender: UITapGestureRecognizer) {
        guard let vc = mainVC?.storyboard?.instantiateViewController(withIdentifier: "diaryDetailViewController") as? DiaryDetailViewController else {return}
   
        vc.modalTransitionStyle = .coverVertical
        vc.modalPresentationStyle = .fullScreen
        
        vc.dateText = diaryTableViewCellDate.text!
        if let emotion = diaryTableViewCellEmotion.text {
            vc.emotionText = emotion
        }
        vc.contentText = diaryTableViewCellContent.text!
        mainVC?.present(vc, animated: true)
        
    }
  • guard let vc = mainVC?.storyboard?.instantiateViewController(withIdentifier: "diaryDetailViewController") as? DiaryDetailViewController else {return} : 스토리보드에서 identifier가 diaryDetailViewController에 해당하는 VC를 인스턴스화합니다.
		vc.dateText = diaryTableViewCellDate.text!
        if let emotion = diaryTableViewCellEmotion.text {
            vc.emotionText = emotion
        }
        vc.contentText = diaryTableViewCellContent.text!

date, emotion, content의 정보들을 인스턴스화 시킨 VC의 변수에 저장시켰습니다. (emotion은 옵셔널이라 바인딩을 사용했습니다.)

각 IBOutlet의 text에 입력하면 되지 않겠냐는 생각이 있었지만 (vc.date = diaryTableViewCellDate.text!)
아마 오류가 나지 않을까 싶습니다. 왜냐면 present 명령어가 실행되지 않았을 때, 그러니까 view가 생성되지 않았을때 접근하기 때문입니다.

결과

다음 글은 삭제 기능을 다루게 되지 않을까 싶습니다. 이 기능을 구현하기 위해서 아마 cell마다 번호를 지정하고 DetailDiaryVC에서 삭제를 누르면 ViewModel에서 번호에 해당하는 일기를 삭제하고 MainVC에서 tableView를 reloadData 해야하지 않을까 싶은데.. 이게 또 나중에 데이터베이스를 구축한다면 다시 코드를 변경 해야하니까 뭘 먼저해야할지 고민이 듭니다..

profile
개발자

0개의 댓글