본 프로젝트는 스파르타 코딩클럽 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 객체들을 구성했다.