날짜별로 섹션을 나누고 싶었는데, 섹션 개수를 나누는 건 쉬웠다.
func numberOfSections(in tableView: UITableView) -> Int {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM월 dd일"
// dueDate를 날짜 형식에 맞게 바꿈. 그리고 중복 없애서 배열에 넣기
let dueDates = Array(Set(toDo.map { dateFormatter.string(from: $0.dueDate) })).sorted()
return dueDates.count
}
근데 이제 문제는 섹션별(날짜별)로 그에 해당하는 데이터만큼 행의 개수를 설정하는 것.
예를 들어 3월 27일에 데이터가 2개다 --> 3월 27일 섹션에 행 2개
내가 원한 건 이런 거였는데, 일단 섹션타이틀이 자꾸 3월 27일이 2개 나왔다. 내가 원한 건 3월 26, 27, 28일 하나씩 나오는거였는데..🥲
일단 섹션 타이틀 부분의 코드는 이렇다.
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM월 dd일"
let dueDates = Array(Set(toDo.map { dateFormatter.string(from: $0.dueDate) })).sorted()
return dueDates[section]
}
GPT랑도 싸우고 블로그를 뒤져본 결과 탄생한 코드...
처음에 GPT는 Calendar.current.isDate() 함수를 자꾸 알려줬다.
그래서 갑자기 무슨 함수인지 공부했다.
두 날짜가 동일한 날짜인지 비교해주는 함수였다.
GPT는 이 함수를 이용해서 동일한 날짜인 것만 남겨서 그걸 섹션타이틀로 만들자는 것이었다. 하지만 이 방법은 잘 통하지 않았고..
let calendar = Calendar.current
let date1 = Date() // 현재 날짜와 시간
let date2 = Date(timeIntervalSinceNow: 3600) // 현재로부터 1시간 후의 날짜와 시간
if calendar.isDate(date1, inSameDayAs: date2) {
print("두 날짜는 동일한 날짜입니다.")
} else {
print("두 날짜는 서로 다른 날짜입니다.")
}
나는 https://gigas-blog.tistory.com/46 이 블로그를 참고해서 해결했다.
다음 문제는 섹션별(날짜별)로 그에 해당하는 데이터만큼 행의 개수를 설정하는 것.
3월 28일의 데이터는 1개인데, 자꾸 2개의 행이 만들어졌다.
이 문제도 아까 참고했다고 한 블로그에서 도움을 받았다.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM월 dd일"
let dueDates = Array(Set(toDo.map { dateFormatter.string(from: $0.dueDate) })).sorted()
// titleForHeaderInSection
let sectionTitle = dueDates[section]
return toDo.filter { dateFormatter.string(from: $0.dueDate) == sectionTitle }.count
}
다음 단계는 섹션별로 알맞은 데이터를 보여주는 것.
이 것은 쉽게 했는데, 다른 문제가 있었다.
스위치가 첫번째 섹션만 동작하고, 다른 섹션은 동작하지 않았다.
프린트 찍어서 스위치가 눌리기는 하는건지도 알아보고, 블로그도 찾아보고, 지피티도 찾아보고 결국 해결!
// @objc func switchValueChanged(_ sender: UISwitch)
// switch의 addTarget으로 들어가는 함수
let dueDates = Array(Set(toDo.map { dateFormatter.string(from: $0.dueDate) })).sorted()
let sectionTitle = dueDates[indexPath.section]
let toDoByDate = toDo.filter { dateFormatter.string(from: $0.dueDate) == sectionTitle }
if let index = toDo.firstIndex(where: { dateFormatter.string(from: $0.dueDate) == sectionTitle && $0.title == toDoByDate[indexPath.row].title }) {
toDo[index].isComplete = sender.isOn
}
원래는 dateTodo만 수정하고 있었는데, dateTodo만 수정하는 건 해당 섹션에 표시되는 할 일 목록만 포함하기 때문에, toDo 데이터를 수정하지 않고 있었다.
toDo.firstIndex(where:): 배열에서 특정 조건을 만족하는 첫 번째 요소의 인덱스를 찾는다. 여기서는 where 절에서 dateFormatter.string(from: $0.dueDate) == sectionDate와 $0.title == dateTodo[indexPath.row].title의 조건을 만족하는 인덱스를 찾는다.dateFormatter.string(from: $0.dueDate) == sectionDate: 선택된 섹션에 해당하는 날짜와 같고,$0.title == dateTodo[indexPath.row].title: 선택된 섹션에서 선택된 행에 해당하는 할 일의 제목과 같은 경우,toDo[index].isComplete = sender.isOn: 찾은 인덱스에 해당하는 할 일의 isComplete 속성을 스위치의 상태에 따라 업데이트한다.// MARK: - Datasource, Delegate
extension ViewController: UITableViewDataSource, UITableViewDelegate {
// Section
func numberOfSections(in tableView: UITableView) -> Int {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM월 dd일"
// dueDate를 날짜 형식에 맞게 바꿈. 그리고 중복 없애서 배열에 넣기
let dueDates = Array(Set(toDo.map { dateFormatter.string(from: $0.dueDate) })).sorted()
return dueDates.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM월 dd일"
let dueDates = Array(Set(toDo.map { dateFormatter.string(from: $0.dueDate) })).sorted()
return dueDates[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM월 dd일"
let dueDates = Array(Set(toDo.map { dateFormatter.string(from: $0.dueDate) })).sorted()
// titleForHeaderInSection
let sectionTitle = dueDates[section]
return toDo.filter { dateFormatter.string(from: $0.dueDate) == sectionTitle }.count
}