본 프로젝트는 스파르타 코딩클럽 iOS 앱개발 부트캠프 과정 중 개인 과제로 작성된 할 일 관리 어플 프로젝트입니다. 모든 프로젝트 파일들은 제 깃허브에 업로드되어 있습니다.
import UIKit
struct Todo {
var todoTitle: String
var todoContents: String
var isCompleted: Bool
}
class TodoListViewController: UIViewController {
// 변수 선언 부분
@IBOutlet var ToDoTableView: UITableView!
static var todoList: [Todo] = [Todo(todoTitle: "11", todoContents: "11111", isCompleted: true)]
static var todoTitleInDetail = String()
static var todoContentsInDetail = String()
static var tempIsCompleted: Bool?
// 함수 선언 부분
override func viewDidLoad() {
super.viewDidLoad()
ToDoTableView.delegate = self
ToDoTableView.dataSource = self
ToDoTableView.reloadData()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
ToDoTableView.reloadData()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
ToDoTableView.reloadData()
}
}
extension TodoListViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TodoListViewController.todoList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = ToDoTableView.dequeueReusableCell(withIdentifier: "ToDoCell", for: indexPath) as! ToDoTableViewCell
cell.setCell(TodoListViewController.todoList[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
TodoListViewController.todoTitleInDetail = TodoListViewController.todoList[indexPath.row].todoTitle
TodoListViewController.todoContentsInDetail = TodoListViewController.todoList[indexPath.row].todoContents
if let ic = TodoListViewController.tempIsCompleted {
TodoListViewController.todoList[indexPath.row].isCompleted = ic
}
print(TodoListViewController.todoList[indexPath.row].isCompleted)
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .delete
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
tableView.beginUpdates()
TodoListViewController.todoList.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
tableView.endUpdates()
}
}
}
Todo
를 선언해줬다.TodoListViewController
에서 관리할 TableView
의 outlet 변수와, 할 일을 탭했을 때 진입할 수 있는 뷰를 제어하는 DetailViewController
에 전해질 임시 변수들을 선언해줬다.viewDidLoad(), viewWillAppear(), viewWillDisappear()
함수 내에 데이터를 가지고있는 TodoTableView
의 역할을 위임, 데이터 관리 권한을 넘겨주는 구문을 작성했다. 또 TableView
의 데이터를 다시 로드하는 구문들도 적어줬다.UITableViewDelegate, UITableViewDataSource
프로토콜에 필히 작성해야 하는 함수들은 아래쪽에 선언했다.tableView
함수에 대해서numberOfRowsInSection
을 갖는 tableView
함수는 데이터 모델의 갯수만큼의 TableViewCell을 만들어주는 역할을 한다.cellForRowAt
을 갖는 함수는 cell
객체를 생성하고 내부에 데이터를 적절히 적용해준다.didSelectRowAt
을 갖는 함수는, cell 내부의 UILabel
을 터치했을 때, DetailView
로 진입할 수 있도록 하는 함수이다.editingStylrForRowAt, editingStyle
을 갖는 두 함수는, cell을 삭제하는 방식과 과정을 결정한다.import UIKit
class TodoTableViewCell: UITableViewCell {
@IBOutlet weak var todoTableTitle: UILabel!
var todoTableContents: String!
@IBOutlet weak var isCompletedSwitch: UISwitch!
var todo: Todo?
override func awakeFromNib() {
super.awakeFromNib()
isCompletedSwitch.setOn(false, animated: true)
automaticallyUpdatesContentConfiguration = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
@IBAction func isCompletedChanged(_ sender: Any) {
guard let todo else { return }
if isCompletedSwitch.isOn {
todoTableTitle?.attributedText = todo.todoTitle.strikeThrough()
} else {
todoTableTitle?.attributedText = todo.todoTitle.nonStrikeThrough()
}
TodoListViewController.tempIsCompleted = isCompletedSwitch.isOn
}
func setCell(_ _todo: Todo) {
todo = _todo
guard var todo else { return }
if todo.isCompleted {
todoTableTitle?.attributedText = todo.todoTitle.strikeThrough()
todo.isCompleted = true
} else {
todoTableTitle?.attributedText = todo.todoTitle.nonStrikeThrough()
todo.isCompleted = false
}
isCompletedSwitch.isOn = todo.isCompleted
}
}
UILabel, UISwitch
의 outlet 변수들과, TodoListViewController 내부의 데이터를 받기 위한 Todo
타입의 todo
변수를 선언했다.awakeFromNib
함수 내부에는 cell 내부의 contents들을 자동으로 업데이트해주는 클래스 변수를 true로 바꿔주었다. (필요한지 모르겠음)UISwitch
를 작동시키면 Todo
내부의 isCompleted
에 변화를 가해주며 UILabel
에 취소선을 적용시키는 작동을 하는 함수 isCompletedChanged()
함수를 작성해줬다.setCell
함수는 TodoListViewController
내부에서 사용할 함수로써, Todo.isCompleted
의 상태에 따라서 취소선 구현을 결정하는 함수이다.import UIKit
class DetailViewController: UIViewController {
@IBOutlet weak var todoTitleLabelinDetail: UILabel!
@IBOutlet weak var todoContentsLabelinDetail: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
todoTitleLabelinDetail.text = TodoListViewController.todoTitleInDetail
todoContentsLabelinDetail.text = TodoListViewController.todoContentsInDetail
todoTitleLabelinDetail.sizeToFit()
todoContentsLabelinDetail.sizeToFit()
}
override func viewDidDisappear(_ animated: Bool) {
todoTitleLabelinDetail.text = ""
todoContentsLabelinDetail.text = ""
}
}
TodoListViewController
에서 선언했던 임시 변수들을 DetailView
내의 UILabel
들에 적용할 수 있도록 하는 구문들을 viewDidLoad
함수 내에 작성해뒀다.DetailView
를 빠져나갈 때, UILabel
들의 내용을 비울 수 있도록 viewDidDisappear
함수 내에 해당 기능을 할 수 있는 구문을 작성했다.import UIKit
class AddTodoViewController: UIViewController {
@IBOutlet weak var todoContentsTextfield: UITextField!
@IBOutlet weak var todoTitleTextfield: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func didAddToDoButtonTapped(_ sender: Any) {
// 제목이나 내용 TextField가 비었을 때 나올 Alert 컨트롤러 객체 생성
let missingTitleAlert = UIAlertController(title: "내용이 모두 입력되지 않았습니다.", message: "빈 칸이 있는지 확인하십시오.", preferredStyle: UIAlertController.Style.alert)
// 정말 추가할 것인지 확인할 때 나올 Alert 컨트롤러 객체 생성
let sureToAddAlert = UIAlertController(title: "할 일 추가", message: "위 내용을 추가하시겠습니까?", preferredStyle: UIAlertController.Style.alert)
// Alert 액션 객체 생성
let addAction = UIAlertAction(title: "추가", style: UIAlertAction.Style.default){ _ in
TodoListViewController.todoList.append(Todo(todoTitle: self.todoTitleTextfield.text!, todoContents: self.todoContentsTextfield.text! ,isCompleted: false))
self.todoTitleTextfield.text = ""
self.todoContentsTextfield.text = ""
self.navigationController?.popViewController(animated: true)
}
let confirmAction = UIAlertAction(title: "확인", style: UIAlertAction.Style.default)
let cancelAction = UIAlertAction(title: "취소", style: UIAlertAction.Style.cancel)
// Alert 컨트롤러에 버튼 추가
missingTitleAlert.addAction(confirmAction)
sureToAddAlert.addAction(addAction)
sureToAddAlert.addAction(cancelAction)
if self.todoTitleTextfield.text == "" || self.todoContentsTextfield.text == "" {
self.present(missingTitleAlert, animated: true)
} else {
self.present(sureToAddAlert, animated: true)
}
}
}
UITextField
에 대한 outlet 변수를 선언했다.didAddTodoButtonTapped
함수 내부에 정의했다.missingTitleAlert
라는 이름의 UIAlertController
객체를 생성해준다.sureToAddAlert
인 UIAlertController
객체를 생성한다.TodoListViewController
내부의 데이터 모델인 todoList
배열에 TextField 내의 데이터들이 입력되도록 하는 구문이 실행된다.UIAlertAction
객체들을 구성했다.