본문 바로가기
iOS Swift/Study

Swift codebase UI - ToDOList UserDefaults 로 데이터 저장하기

by 야고이 2024. 5. 3.
728x90

240502

지난 투두리스트 만들 때는 스토리보드로 만들었는데 이번에 코드만으로 만들어 봤다

UI 도 좀 바꿔서 함

 

 

화면 구성 

Snapkit 사용

화면 상단 TextField 에 위치시키고 내용을 적고 키보드 상에서 Done을 누르면 리스트가 추가 됨

Userdefaults 로 데이터 저장

스와이프로 삭제

(이건 아직 안함!!)할 일 완료시 리스트 하나를 클릭하면 취소선, 텍스트 회색으로 바뀜

 

코드 짠 순서대로 기록해 볼까 한다

 

Struct 생성

struct Task : Codable {
    let title: String // 타이틀. 할 일 내용
    var done: Bool // 완료 여부
}

 

 

담을 빈 배열 생성

var toDoList = [Task]()

 

 

텍스트필드, 테이블뷰 생성

let textField = UITextField()
let tableView = UITableView()

 

 

오토레이아웃

func setupConstraints() { // addSubview, 오토레이아웃 등
    view.addSubview(textField)
    view.addSubview(tableView)

    textField.snp.makeConstraints {
        $0.top.equalTo(view.safeAreaLayoutGuide)
        $0.leading.equalToSuperview().offset(24)
        $0.trailing.equalToSuperview().offset(-24)
        $0.height.equalTo(50)
    }

    tableView.snp.makeConstraints {
        $0.top.equalTo(textField.snp.bottom).offset(20)
        $0.leading.trailing.bottom.equalToSuperview()
    }
}

 

속성 값 설정

func configureUI() { // UI 요소들의 속성을 대입(컬러, text 등)
    view.backgroundColor = .systemBackground

    textField.borderStyle = .roundedRect   // 테두리 스타일
    textField.layer.borderColor = UIColor.systemGray.cgColor
    textField.layer.borderWidth = 2.0
    textField.layer.cornerRadius = 5
    textField.placeholder = "할 일이 뭔데"
    textField.clearButtonMode = .always    // 입력내용 한번에 지우는 x버튼(오른쪽)
    textField.clearsOnBeginEditing = false // 편집 시 기존 텍스트필드값 제거?
    textField.returnKeyType = .done

    tableView.backgroundColor = .systemBackground
    tableView.register(ToDoListTableViewCell.self, forCellReuseIdentifier: ToDoListTableViewCell.identifier)

}

 

화면 터치하면 키보드 내려감

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?){
    self.view.endEditing(true)
}

view 전체적으로 테이블뷰가 깔려 있어서 키보드 부분 제외하고 나머지 아무곳이나 클릭해서 내려가지 않고

텍스트필드 밑에 약간 깔린 뷰쪽만 클릭이 먹는다

일단 이게 중요한게 아니어서 패스하지만 고쳐놔 봐야지

 

텍스트 필드에서 Done 을 하면 테이블뷰에 리스트가 추가

extension ViewController: UITextFieldDelegate {
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        print("textFieldShouldReturn: \(textField.text ?? "")")
        textField.resignFirstResponder() // Done 누르면 키보드 내려감
        
        guard let title = textField.text else { return false }
        self.addToDoItem(title: title)
        print("[toDoList] \([toDoList])")
        textField.text = "" // 텍스트 필드 안에 텍스트 비움
        tableView.reloadData()
        return true
    }
}

테이블 뷰에 추가하는건 따로 함수를 만들어서 넣었다

 

리스트에 추가 함수

func addToDoItem(title: String) {
    self.toDoList.append(Task(title: title, done: false)) //리스트에 할 일 추가해줌
    saveData()
    print("리스트에 할 일 추가")
    self.tableView.reloadData() //추가한 리스트를 보여줌
    print("할 일 추가 후 reloadData")
}

완료 여부인 bool 값은 일단 다 false로 넣어줌

그리고 이걸 저장하는 함수도 따로 만들어 주었다

반드시 releadData 할 것!

 

UserDefaults 로 저장하는 함수

func saveData() {
    let toDoList = self.toDoList.map { task in
        ["title": task.title, "done": task.done]
    }
    UserDefaults.standard.setValue(toDoList, forKey: "ToDoList")
}

map 을 사용해서 하나씩 배열에 저장 됨

 

데이터를 로드하는 함수

func loadData() {
    print("loadData")
    guard let toDoList = UserDefaults.standard.value(forKey: "ToDoList") as? [[String : Any]] else { return }

    self.toDoList = toDoList.compactMap { todo -> Task? in
        guard let title = todo["title"] as? String, let done = todo["done"] as? Bool else { return nil }
        return Task(title: title, done: done)
    }
}

데이터가 로드되는건 viewDidLoad 에서 진행 된다

 

override func viewDidLoad() {
    super.viewDidLoad()
    setupConstraints()
    configureUI()

    textField.delegate = self
    tableView.delegate = self
    tableView.dataSource = self
    loadData()
}

위에서 작성한 오토레이아웃과 속성값 그리고 loadData를 넣어주고

테이블뷰와 텍스트 필드의 delegate,dataSource 도 대리자 위임하는거 잊지 말기!!

 

테이블뷰  delegate, datasource

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    toDoList.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: ToDoListTableViewCell.identifier, for: indexPath) as? ToDoListTableViewCell else  { return ToDoListTableViewCell() }

    let toDoList = toDoList[indexPath.row]
    cell.title.text = toDoList.title
    cell.selectionStyle = .none
    return cell
}

배열에 들어온 수 만큼 셀을 뿌리고

셀의 텍스트는 입력한 텍스트가 들어 갑니다

 

그리고 매번 방법을 까먹어서 검색하는,, 기본값으로 셀을 선택하면 선택한 셀이 회색으로 되는데

cell.selectionStyle = .none

요걸로 그 설정을 꺼줍니다

 

스와이프로 해당 셀 삭제

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 {
            toDoList.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)
            saveData()
        } else if editingStyle == .insert {
            
        }
    }

셀의 설정을 .delete 로 설정해 줍니다

삭제 될때 먼저 배열에 해당하는 값을 지워주고

테이블뷰에 해당하는 셀을 지워줍니다

그리고 saveData 로 데이터를 저장해 주면 끝

 

저번 투두리스트 만들 때 saveData 가 들어가는 순서에 따라 오류가 났었던 기억이 나는데 

일단 지금은 오류가 안나므로 여기서 마무리 하겠슴다

 

완료시 텍스트 설정이 바뀌는 것도 하게 되면 추가해 둘게요!

728x90

댓글