My Todo List
어제 그리고 오늘은 ToDo 내용 수정과 메모 추가 기능을 만들었다.
'사실 처음에는 또 쉽겠지(ㅋ)' 하고 쉽게 봤다.
그렇다. 또 큰 코를 다치고 말았다. 난 지금 코가 없다.
코가 없어진 과정에 대해,
처음 생각은 그랬다,
'변수를 추가하고 테이블 뷰에 사용자가 입력한 값을 ViewController로 전달해 구조체의 값을 변경하면 되겠지.'
...누구나 그럴듯한 계획은 가지고 있다. 생각만으로는 지구정복도 가능하다는 사실을 망각한 대가가 너무 크다.
ViewController.swift
struct TodoItem {
static var nextId = 1
var id: Int
var title: String
var isCompleted: Bool
var memo: String?
var saveDate: String
init(title: String, isCompleted: Bool = false, date: Date = Date(), memo: String? = nil) {
self.id = TodoItem.nextId
self.title = title
self.isCompleted = isCompleted
self.memo = memo
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy년 MM월 dd일"
self.saveDate = dateFormatter.string(from: date)
TodoItem.nextId += 1 // 아이디 +1
}
}
// 생략
func detailViewControllerDidSave(todoItem: TodoItem) {
if let index = todos.firstIndex(where: { $0.id == todoItem.id }) {
todos[index] = todoItem
if let tableView = tableView {
tableView.reloadData()
} else {
print("tableView가 nil입니다.")
}
}
}
메모에 대한 값을 저장하기 위해 제일 먼저 구조체에 변수를 추가했다. 그리고, DetailViewController
에서 수정된 TodoItem
을 저장할 때 호출할 메서드를 작성했다. 수정된 TodoItem
의 id
를 사용하여 todos
배열에 해당 아이템의 인덱스를 찾고, 수정된 TodoItem
으로 해당 아이템을 업데이트, tableView
가 있는 경우 리로드 하여 변경사항을 반영하도록 하였다.
- 수정된 TodoItem
의 id
를 사용하여 todos
배열에서 해당 아이템의 인덱스 찾기
→ TodoItem
의 해당되는 위치에 아이템 업데이트
- tableView
가 있는 경우
→ 해당 테이블 뷰를 리로드 하여 변경 사항을 반영
→ 만약 tableView
가 nil
이라면 콘솔에 메시지 출력
DetailViewController.swift
// DetailViewController의 수정된 Todo 아이템을 저장하는 데 사용되는 메서드를 정의한 protocol
protocol DetailViewControllerDelegate: AnyObject {
func detailViewControllerDidSave(todoItem: TodoItem)
}
class DetailViewController: UIViewController, UITextViewDelegate {
// delegate 속성 선언
weak var delegate: DetailViewControllerDelegate?
// 생략
var todoItem: TodoItem? // 전달된 TodoItem을 저장할 변수
// 생략
// MARK: - Save Button Action / ToDo 수정 및 메모 저장 동작
@IBAction func saveButtonTapped(_ sender: UIBarButtonItem) {
// 텍스트뷰가 비어 있는지 확인
guard let text = textView.text, !text.isEmpty else {
// 텍스트뷰가 비어 있으면 알림 표시
let alertController = UIAlertController(title: "알림", message: "ToDo를 입력해 주세요.", preferredStyle: .alert)
let okAction = UIAlertAction(title: "확인", style: .default, handler: nil)
alertController.addAction(okAction)
present(alertController, animated: true, completion: nil)
return
}
// 수정된 TodoItem 생성
var updatedTodoItem = todoItem ?? TodoItem(title: "") // 기존 TodoItem이 없으면 빈 TodoItem 생성
// 수정된 값을 TodoItem의 title에 저장
updatedTodoItem.title = text
// 입력된 값을 TodoItem의 memo에 저장
updatedTodoItem.memo = memoView.text
// delegate를 통해 수정된 TodoItem을 ViewController로 전달
delegate?.detailViewControllerDidSave(todoItem: updatedTodoItem)
// 이전 화면으로 이동
navigationController?.popViewController(animated: true)
}
}
DetailViewController
에서는 수정된 Todo
아이템을 저장하는 데 사용하는 메서드를 정의한 protocol
를 작성했다. DetailViewControllerDelegate
프로토콜을 준수하는 객체를 약한 참도로 저장하는 속성을 가진 delegate
를 선언했다. 그리고 todoItem
변수를 선언하여 저장 버튼 클릭 시 호출되는 saveButtonTapped(\_:)
함수를 구현했다. 먼저 텍스트 뷰의 isEmpty
여부를 확인하고 비어있다면 알림을 표시, 그렇지 않을 경우 입력된 값들을 TodoItem
저장, 수정된 TodoItem
을 delegate
을 통해 전달하도록 했다.
- DetailViewControllerDelegate
프로토콜
→ detailViewControllerDidSave(todoItem:)
메서드 요구
→ 수정된 TodoItem
을 저장하기 위해 사용
- DetailViewController
클래스
→ UIViewController
를 상속받음
→ UITextViewDelegate
프로토콜을 따름
- delegate
→ DetailViewControllerDelegate
프로토콜을 준수하는 객체를 약한 참조로 저장
- todoItem
속성은 전달된 TodoItem
저장
- saveButtonTapped(\_:)
→ 저장 버튼이 눌렸을 때 호출
→ 텍스트뷰가 비어 있는지 확인하고 비어 있다면 알림 표시
→ 그렇지 않을 경우, 입력된 값들을 TodoItem
객체에 저장, 수정된 TodoItem
을 delegate
를 통해 전달
그러니까, 이렇게 하면 되는데 계속 데이터가 변경되지 않아서 어제도 오늘도 내내 이 코드 내에서 뭐가 잘못된 건지 몰라서 한참을 헤맸다.
근데 확인해 보니
스토리보드에서 tableView
아웃렛이 제대로 연결이 안 되어있었다. ᕕ( ᐛ )ᕗ
진짜 황당하고... 분명 연결했다고 생각했는데 아니었다.
어쨌든 해결완료! 이제 ToDo 수정과 Memo를 남길 수 있게 되었다.
Placeholder 설정
memoView.text = placeholderText
memoView.textColor = UIColor.lightGray
// 생략
func textViewDidBeginEditing(_ textView: UITextView) {
if memoView.text == placeholderText {
memoView.text = ""
memoView.textColor = UIColor.black
}
}
func textViewDidChange(_ textView: UITextView) {
if memoView.text.isEmpty {
memoView.text = placeholderText
memoView.textColor = UIColor.lightGray
}
}
이틀간 헤매던 걸 해결한 기쁨으로 간단하게 placeholder
까지 설정해 줬다.
- memoView.text
에 placeholderText
를 할당하여 플레이스홀더를 설정
- textViewDidBeginEditing(\_:)
→ 텍스트 뷰가 편집 모드로 전환될 때 호출
→ 이때, 텍스트 뷰에 입력이 감지될 경우 placeholder
를 지우고 텍스트가 입력됨
- textViewDidChange(\_:)
→ 텍스트 뷰의 내용이 변경될 때마다 호출
→ 여기서는 텍스트 뷰가 비어 있는 경우 플레이스홀더를 다시 표시
늘 느끼지만 한 번 더, 꼭 확인하자.
'𝗔𝗦𝗦𝗜𝗚𝗡𝗠𝗘𝗡𝗧 > [내배캠] 4주차 - ToDo' 카테고리의 다른 글
[내일배움캠프] iOS 입문 과제 - My Todo List(01) | 뭐가 나왔다고, 아주 험한 게(feat. 파묘) (3) | 2024.03.21 |
---|