자세한 코드는 여기로!
8/16
어제 했던 Storage에 이어, 이번엔 싱글톤 객체를 만들 Todo.swift 파일을 작성해보겠다.
Todo.swift 파일에는 Todo를 작성하는데 필요한 데이터를 묶어놓은 구조체와 싱글톤 객체를 위한 클래스가 생성될 것이다.
싱글톤 객체?
- 만들어진 인스턴스를 only 최초로 전역에 두고, 그 이후로 그냥 이 인스턴스만 사용! 접근!
- 여기서는 TodoManager가 싱글톤 객체
- 이 TodoManager안에는 Todo를 만들고 삭제, 업데이트, 저장, 획복시키는 로직이 있어야 함
이렇게 만들어진 구조체와 클래스(Todo.swift)
import UIKit
// TODO: Codable과 Equatable 프로토콜 추가
// Codable : JSON 파일을 Swift가 알아들을 수 있게 바꿔줌
// Equatable : 여기서는 '=='의 조건을 정의해 줄 수 있음( 값이 동등한지 ), 사용자가 손쉽게 정의할 수 있도록 해줌
struct Todo: Codable, Equatable {
let id: Int
var isDone: Bool
var detail: String
var isToday: Bool
// 구조제에 선언된 프로퍼티를 변경하기 위해서는 함수앞에 mutating 키워드 붙여주기
mutating func update(isDone: Bool, detail: String, isToday: Bool) {
//값타입인 struct는 속성을 인스턴스 메서드 내에서 수정할 수 없음
// 수정하려면 mutating 키워드 추가
// TODO: update 로직 추가
self.isDone = isDone
self.detail = detail
self.isToday = isToday
}
static func == (lhs: Self, rhs: Self) -> Bool {
// TODO: 동등 조건 추가
return lhs.id == rhs.id
}
}
class TodoManager {
static let shared = TodoManager()
static var lastId: Int = 0
var todos: [Todo] = []
// TODO: create 로직 추가
func createTodo(detail: String, isToday: Bool) -> Todo {
let nextId = TodoManager.lastId + 1
TodoManager.lastId = nextId
return Todo(id: nextId, isDone: false, detail: detail, isToday: isToday) // 왜 isToday는 Bool 값으로 안주지?
}
// TODO: add 로직 추가
func addTodo(_ todo: Todo) {
todos.append(todo)
saveTodo()
}
// TODO: delete 로직 추가
func deleteTodo(_ todo: Todo) {
todos = todos.filter{ $0.id != todo.id }
saveTodo()
}
// TODO: update 로직 추가
func updateTodo(_ todo: Todo) {
// firstIndex(of:) 는 배열의 앞에서부터 조회해서 todo와 첫번째 일치하는 값의 index를 반환
guard let index = todos.firstIndex(of: todo) else { return }
todos[index].update(isDone: todo.isDone, detail: todo.detail, isToday: todo.isToday)
saveTodo()
}
// TODO: save 로직 추가
func saveTodo() {
Storage.store(todos, to: .documents, as: "todo.json")
}
// TODO: retrieve 로직 추가
func retrive() {
todos = Storage.retreive("todos.json", from: .documents, as: [Todo].self) ?? []
let lastId = todos.last?.id ?? 0
TodoManager.lastId = lastId
}
}
이제 이어서 TodoViewModel도 Todo.swift에 만들어줄건데,
TodoViewModel은 뭘하는 애냐면,, (이걸보는 중엽님.. 뭔가 이상하다면 댓글이나 디코..ㅋㅋㅋㅋㅎ)
앞서 만든 TodoManager 객체를 private 인스턴스로 가져와서 화면에 말그대로 view model! 화면에 뿌려주는 모델 역할을 한다..!
todos를 가져와 Today todos, Upcoming todos, 각 today와 upcomming의 섹션 개수를 나타내주고
화면에서의 todo 추가, 삭제, 업데이트, 회복도 나타나게 해주는 것
즉, viewController에서는 얘만 다루면 오케이~
class TodoViewModel {
enum Section: Int, CaseIterable {
case today
case upcoming
var title: String {
switch self {
case .today: return "Today"
default: return "Upcoming"
}
}
}
private let manager = TodoManager.shared
var todos: [Todo] {
return manager.todos
}
var todayTodos: [Todo] {
return todos.filter { $0.isToday == true }
}
var upcompingTodos: [Todo] {
return todos.filter { $0.isToday == false }
}
var numOfSection: Int {
return Section.allCases.count
}
func addTodo(_ todo: Todo) {
manager.addTodo(todo)
}
func deleteTodo(_ todo: Todo) {
manager.deleteTodo(todo)
}
func updateTodo(_ todo: Todo) {
manager.updateTodo(todo)
}
func loadTasks() {
manager.retrieveTodo()
}
}
이렇게 정신없게 쓰고 있는 와중, 머릿속도 정신없어서 중엽님의 깔끔한 로직 정리를 가져와보겠다 (감사합니다..🥺)
📌Todo.swift 정리
- Todo 구조체 : 가장 작은 단위의 todo
- TodoManager 클래스 : 실질적인 모든 기능을 수행하는 싱글톤 객체 정의
- TodoViewModel : TodoList (최종) 모델, TodoManager를 이용하여 Todo 리스트에 접근, 수정 등 가능
자, 이제 Todo.swift 와 Storage.swift 파일을 통해 Todo를 관리하고 디테일한 기능을 정리할 수 있게되었다.
다음은 저번에 화면구성하다가만 collectionViewCell을 정의하고 마무리 하겠다.
(음 .. 근데 cell 파일을 항상 나는 따로 만들었는데 내가 지금 공부하는 파일에는 cell의 업데이트 로직이 그냥 view controller에 다 있어서 나도 TodoListViewController.swift 파일에 다 코드를 넣음!)
- collectionView의 Cell 의 identifier와 class name을 TodoListCell 로 설정
- ViewController에서 UICollectionViewCell 클래스 만들어주기
- 컴포넌트 연결
내일은 tabbar controller 해봐야지
'iOS > Toy project' 카테고리의 다른 글
[iOS : Toy Project] Todo List 만들기 (4) - CollectionView의 Datasource, Delegate (0) | 2022.08.19 |
---|---|
[iOS : Toy Project] Todo List 만들기 (3) (0) | 2022.08.17 |
[iOS : Toy Project] Todo List 만들기 (1) (0) | 2022.08.15 |
[iOS : Toy Project] Github Profile (2) : Refactoring (0) | 2022.07.17 |
[iOS : Toy Project] Github Profile (1) (0) | 2022.07.16 |