[iOS] Swift에서 날짜 기반 채팅 목록 그룹화 개선하기 (Feat. 그룹화 우선순위의 오류, sortWeight)
ㅡAloneChat의 groupChatRoms() 정렬 문제 해결 과정에 대해 다루고 있습니다.
1. 문제 정의 : 연도별 정렬 오류
AloneChat에는 채팅 목록을 날짜별로 그룹화하는 기능이 있습니다. 이 기능은 2024년 연말까지는 문제없는 듯 보였지만, 2025년 새해가 되면서(ㅋㅋ ㅠㅠ 바보...) 2024년 그룹이 2025년 1월보다 위에 표시되는 문제가 발생하였습니다.
내가 기대하는 정렬
- 오늘
- 어제
- 02월 (2025년 2월)
- 01월 (2025년 1월)
- 2024년 (이전 연도는 한 그룹으로 묶음)
현재 코드에서 발생하는 문제
2024년이 2025년 1월보다 위에 정렬되는 것이 문제가 됩니다.
2. 문제 원인 분석
이전에는 Dictionary<String, [ChatRoom]> 형태로 반환한 뒤, Dictionary의 Key인 문자열(오늘, 내일 등의 문자 표시)를 문자열 내림차순으로 정렬하고 있었습니다...
ㅡ정말 대충격입니다... AloneChat 개발을 시작한 10월부터 "오늘, 내일, 12월, 11월, 10월"의 정렬만 봤기에 지금까지는 문제가 없는 줄 알았습니다. 지금까지의 방식은 아래와 같은 문제가 생길 수 있습니다.
- "오늘", "어제" 등 문자표기가 들어오면 사전순과 의도한 순서가 엇갈릴 수 있다는 것.
- 한글, 숫자, 연도("2024년")를 단순 문자열로 정렬하면 예기치 못한 순서가 만들어진다는 것.
- 결국 2025년 1월과 2024년이 서로 정확히 어떤 순서로 비교되어야 하는지, 문자열 비교만으로는 해결할 수 없다는 것.
3. 해결 방법: 그룹 우선순위 + 정렬된 배열 의 반환
제가 원하는 건 "오늘 → 어제 → 올해(월 순서) → 이전 연도(연 순서)" 정렬입니다. 이를 위해 sortWeight(우선순위)를 부여해 "그룹별" 정렬 기준을 명확히 하고, 그 결과를 기존 Dictionary 대신, 이미 정렬된 배열의 형태로 만들어서 UI에 넘기면 됩니다. (그리고 UI에서는 배열 그대로 사용하면 되죠.)
- sortWeight 도입
- 오늘 (3) > 어제 (2) > 현재 연도 월별 (1) > 이전 연도 (0)
- 같은 우선순위 내에서는 날짜 내림차순으로 정렬 (예: 2월 > 1월)
- 최종 반환은 [(groupKey: String, rooms: [ChatRoom])] 형태의 정렬된 배열
- Dictionary를 사용하면 키 정렬에 또다시 사전식 분류가 들어가 정렬 순서가 뒤죽박죽됩니다.
- 배열로 준다면 ForEach로 배열을 그대로 순회해, 원하는 순서를 확실히 유지할 수 있습니다.
4. 해결 코드
private func groupChatRooms(_ chatRooms: [ChatRoom]) -> [(groupKey: String, rooms: [ChatRoom])] {
let dateFormatter = DateFormatter()
let calendar = Calendar.current
let today = calendar.startOfDay(for: Date())
let yesterday = calendar.date(byAdding: .day, value: -1, to: today)
let currentYear = calendar.component(.year, from: today)
// (키, 날짜, 우선순위, ChatRoom)을 임시 저장할 배열
var groupedRooms: [(key: String, date: Date, sortWeight: Int, rooms: [ChatRoom])] = []
for chatRoom in chatRooms {
let chatDate = calendar.startOfDay(for: chatRoom.lastTimestamp)
let chatYear = calendar.component(.year, from: chatRoom.lastTimestamp)
let groupKey: String
let sortWeight: Int
if chatDate == today {
groupKey = Constants.ChatList.today
sortWeight = 3
} else if chatDate == yesterday {
groupKey = Constants.ChatList.yesterday
sortWeight = 2
} else if chatYear == currentYear {
dateFormatter.dateFormat = Constants.ChatList.currentYearFormat
groupKey = dateFormatter.string(from: chatRoom.lastTimestamp)
sortWeight = 1
} else {
dateFormatter.dateFormat = Constants.ChatList.previousYearFormat
groupKey = dateFormatter.string(from: chatRoom.lastTimestamp)
sortWeight = 0
}
if let index = groupedRooms.firstIndex(where: { $0.key == groupKey }) {
groupedRooms[index].rooms.append(chatRoom)
} else {
groupedRooms.append((key: groupKey, date: chatDate, sortWeight: sortWeight, rooms: [chatRoom]))
}
}
// 1) 그룹 우선수누위 내림차순
// 2) 우선순위가 같으면 날짜 내림차순
groupedRooms.sort {
if $0.sortWeight == $1.sortWeight {
return $0.date > $1.date
}
return $0.sortWeight > $1.sortWeight
}
// 이미 정렬된 상태의 (groupKey, rooms) 배열 반환
return groupedRooms.map {
(groupKey: $0.key, rooms: $0.rooms)
}
}
5. 결론
한동안 별 문제 없을 거라 생각했던 정렬 로직이, 새해가 되면서 갑자기 꼬이는 일이 났습니다.(ㅋㅋ ㅠㅠ) 원인은 Dictionary의 키 정렬 방식이 제가 기대한 "날짜 우선순위"와 맞지 않았기 떄문이었죠...
이를 해결하기 위해 우선순위(sortWeight)를 도입해 정렬 기준을 명확히 했을 뿐만 아니라, 순서를 보장하지 않는 Dictionary 대신, 이미 정렬된 배열을 반환하는 방식으로 변경했습니다.
- Dictionary는 키 정렬이 필요하고, 사전식 정렬이 원하는 순서와 다를 수 있다는 한계를 직접 경험했고,
- 배열로 반환하면 View에서 별도의 정렬 작업 없이 원하는 순서를 그대로 사용할 수 있다는 점을 깨달았습니다.
비슷한 정렬 이슈가 발생한다면, 우선순위를 정의하는 것뿐만 아니라, 최종적으로 정렬된 배열을 반환하는 구조인지도 함께 고민해봐야 한다는 교훈을 얻었습니다.
(혹시 아직도 Dictionary로 정렬 후 .keys.sorted(by: >) 같은 코드 쓰고 계신다면… 한 번쯤 다시 생각해보시길!🔥)