코드 레포
https://github.com/yenny42/nbc_camp/tree/main/iOSBasic_MyToDoList
문법 주차를 전부 끝내고 진입한 앱 개발 입문 주차. 2주간의 기간이 주어졌다
이제는 콘솔에서 동작하는 프로그램이 아닌 제대로 된 xcode project를 생성해서 진행한다.
기록용으로 간략하게 적는 1인 회고라서.. 그냥 러프하게 적어보기로 했다
🩵 미리보는 최종화면
❓ 개발 기능 조건
LV1. Todo List 화면 만들기
LV2. Todo 추가 및 완료 기능 구현하기
LV3. Todo 삭제 기능 구현하기
Lv4. Todo Cell 발전시키기
Lv5. 할일 추가 등 animation이 있는 코드 구성하기
총 5개의 조건이 있었고 레벨 3 까지가 필수 구현 조건이었다.
🩵 LV1. Todo List 화면 만들기
코드로 화면을 짜는 것도 배우긴 했지만 아직은 너무 어렵게 느껴졌다.
구현 조건에도 굳이 코드로 짜지 않아도 됩니다!! 라고 하였기 때문에.. 스토리보드로 만들었다.
- UITableView, UITableViewCell
- UILabel
- UIButton
위 4가지를 사용해서 메인화면을 구성했다.
AutoLayout을 적용하니 다른 크기의 시뮬레이터로 빌드해도 위치가 잘 적용되어 있어서 좋았다.
🩵 LV2. Todo 추가 및 완료 기능 구현하기
✔️ Navigation Controller
처음에 이 메인화면만 두고 기능을 만들다가 나중에 추가적인 페이지의 필요성을 느꼈다.
특히 To do 를 등록하기 위한 값을 alert의 textfield로 받았는데, date picker가 UI적으로 말썽을 부린 것이 가장 큰 원인이다.
Storyboard에 navigation controller를 걸어서 페이지 이동을 할 수 있게 해 주었다.
🦋 To do 추가하기
textField로 값을 입력 받고 마감일을 date picker로 선택해줄 수 있다.
등록 버튼을 누르면 메인 화면의 data 배열에 값이 추가되고 tableview에 새로 그려진다.
✔️ Protocol을 사용한 데이터 전달
입력한 값을 다시 원래 사용하던 tableview 데이터에 추가하기 위해서 protocol을 사용했다.
아래 DataDelegate 프로토콜을 채택하는 객체는 Todo타입의 data를 전달받을 수 있다.
나는 ViewController의 데이터 배열에 추가할 것이기 때문에 ViewController에 DataDelegate 프로토콜을 채택한 뒤 sendData를 구현했다.
protocol DataDelegate: AnyObject {
func sendData(data: Todo)
}
struct Todo {
var title: String
var isComplete: Bool
var regDate: String
var dueDate: String
}
class ViewController: UIViewController, DataDelegate {
.
.
.
func sendData(data: Todo) {
testData.append(data)
TodoListTableView.beginUpdates()
TodoListTableView.insertRows(at: [IndexPath(row: self.testData.count - 1, section: 0)], with: .automatic)
TodoListTableView.endUpdates()
}
}
sendData에서는 data를 tableViewCell에 사용하는 데이터 배열에 추가해 준 다음,
tableView를 새로 불러온다. (관련 포스팅 -> 링크)
class AddTodoVC: UIViewController {
. . .
weak var delegate: DataDelegate?
. . .
@IBAction func AddTodoButton(_ sender: UIButton) {
inputData = Todo(title: todoTextField.text!, isComplete: false, regDate: todayLabel.text!, dueDate: dueDatePicker.date.toString("yy.M.d"))
if self.inputData.title == "" {
warningText()
} else {
delegate?.sendData(data: inputData)
navigationController?.popViewController(animated: true)
}
}
. . .
}
delegate는 DataDelegate 프로토콜을 채택한 객체를 참조할 수 있는 변수이다.
내 경우에는 ViewController가 되겠다.
delegate?.sendData(data: inputData)
이렇게 내가 입력받아 Todo 타입으로 만든 inputData를 data에 담아서 ViewController로 보내줄 수 있다.
그러면 ViewController는 sendData를 구현해서 받은 데이터를 사용할 수 있는 것이다!!
✔️ 추가기능 : textField가 비어있다면?
만약 textField를 입력하지 않았다면 입력하라고 warning용 label을 보여준다.
label은 기본적으로 clear color로 만들어두고 조건에 해당할 때 red로 바뀐다.
func warningText() {
warningTitleLabel.textColor = .systemRed
}
🦋 To do 완료하기
Bool 값을 반전해주는 toggle 메소드를 사용하여 투두 데이터의 완료 여부를 체크했다.
@objc func checkBoxButtonTapped(sender: UIButton) {
guard let cell = sender.superview?.superview as? ToDoListTableViewCell else {
return
}
let index = sender.tag
testData[index].isComplete.toggle()
cell.isComplete = testData[index].isComplete
}
ViewController 클래스 내부에서 해당하는 인덱스의 isComplete값을 바꿔준다.
그런 다음에 table view cell 내부의 isComplete 변수를 변경한다.
var isComplete: Bool = false {
didSet {
if isComplete == true {
todoCompleteButton.tintColor = UIColor.systemRed
todoTitleLabel.textColor = UIColor.lightGray
todoDateLabel.textColor = UIColor.lightGray
todoDueDateLabel.textColor = UIColor.lightGray
} else {
todoCompleteButton.tintColor = UIColor.lightGray
todoTitleLabel.textColor = UIColor.black
todoDateLabel.textColor = UIColor.black
todoDueDateLabel.textColor = UIColor.black
}
}
}
프로퍼티 옵저버를 사용하여 값이 바뀔 때 특정한 행동을 할 수 있게 해 보았다.
ViewController 클래스에서 변경되어 새로 입력받은 isComplete값에 따라 완료, 미완료 여부에 맞게 스타일을 변경한다.
내가 쓴 코드는 모든 UILable이 회색으로 변하고 하트모양 check 버튼은 빨간색으로 차오르게 한다.
🩵 LV3. Todo 삭제 기능 구현하기
// MARK: Delete Table View Cell
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
// MARK: Click delete of Swipe delete
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let deletedData = self.testData[indexPath.row]
tempDeleteVC.setTempData(data: deletedData)
self.testData.remove(at: indexPath.row)
TodoListTableView.beginUpdates()
TodoListTableView.deleteRows(at: [indexPath], with: .fade)
TodoListTableView.endUpdates()
}
}
ViewController의 테이블 뷰에서 사용하는 데이터 배열에서 해당하는 부분을 remove 한 다음
테이블 뷰를 업데이트 해준다. (deleteRows 사용)
✔️ 추가기능 : 전체 삭제
우측 상단의 휴지통 버튼을 누르면 alert창을 통해 데이터를 전체 삭제할 수 있게 해 주었다
func allClearButtonAlert() {
let alert = UIAlertController(title: "전부 삭제하시겠습니까?", message: "복구가 불가능합니다.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Default action"), style: .destructive, handler: { _ in
self.testData.removeAll()
self.TodoListTableView.reloadData()
}))
alert.addAction(UIAlertAction(title: NSLocalizedString("취소", comment: ""), style: .default))
self.present(alert, animated: true, completion: nil)
}
🩵 Lv4. Todo Cell 발전시키기
✔️ Date picker / compare() 메소드
사실 위에 이미 언급 된 마감일 date picker가 이 레벨 4부분으로 구현한 것이다..
date picker로 선택한 날짜를 dueDate 부분에 담아서 보여주는 식으로 개선했다.
@IBOutlet weak var dueDatePicker: UIDatePicker!
@IBAction func AddTodoButton(_ sender: UIButton) {
let compareDate = (dueDatePicker.date.toString("yyMMdd")).compare(Date().toString("yyMMdd"))
if compareDate != .orderedAscending {
inputData = Todo(title: todoTextField.text!, isComplete: false, regDate: todayLabel.text!, dueDate: dueDatePicker.date.toString("yy.M.d"))
if self.inputData.title == "" {
warningText()
} else {
delegate?.sendData(data: inputData)
navigationController?.popViewController(animated: true)
}
} else {
warningDatePicker()
}
}
compare 메소드를 사용해서 입력한 마감일과 오늘 날짜를 비교한다.
비교했을 때, 입력한 마감일이 오늘보다 이전이라면 alert창을 띄워 불가능하다는 내용을 표시해주었다.
func warningDatePicker() {
let alert = UIAlertController(title: "날짜를 다시 골라주세요.", message: "오늘 이전의 날짜는 마감일로 설정할 수 없습니다.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default))
self.present(alert, animated: true, completion: nil)
}
🩵 Lv5. 할일 추가 등 animation이 있는 코드 구성하기
이것도 이미 위에서 insertRows, deleteRows 등을 하며 animated를 넣었기 때문에 패스하도록 하겠다
🔥 최종적인 후기
데이터를 전달하기 위해 delegate 패턴을 사용해 본 것이 가장 재미있었다.
연결하는 데 약간.. 많이..? 애를 먹긴 했지만 연결을 해 놓고 보니 생각보다 간단했다.
delegate에 대해 좀 자세하게 파봐야 할 것 같당
진행하는 기간동안 비도 오고 눈도 오고 날이 더웠다 추웠다 아주 난리 부르스여서 컨디션이 꽝이었다.
그래서 생각했던 것 보다 넣고싶다고 생각했던 추가적인 옵션기능을 못 만든 것 같아서 아쉽다. 추후 꾸준히 고쳐나가고 싶다
✔️ 추가적으로 넣고싶은 기능
일단 휴지통을 만들어서 temp delete를 할 수 있게 만들고싶다.
그리고 이미 등록해 둔 투두를 수정하는 기능이려나..
'내일배움캠프 iOS 2기' 카테고리의 다른 글
[트러블슈팅] 앱개발심화(개인) - 이미지 로딩 및 재사용 문제 해결 (2) | 2024.01.31 |
---|---|
[NBCAMP] 3팀-SPABUCKS (OrderListView)코드 기능 정리 (0) | 2023.12.29 |