-
[iOS] Swift에서 날짜 기반 채팅 목록 그룹화 개선하기 (Feat. 그룹화 우선순위의 오류, sortWeight)IT Study/iOS 2025. 1. 30. 17:01728x90
"01월"은 2025년 1월이다... ㅡ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: >) 같은 코드 쓰고 계신다면… 한 번쯤 다시 생각해보시길!🔥)
후련하게 해결한 사진까지 투척... 'IT Study > iOS' 카테고리의 다른 글
[iOS] 테스트 플라이트 "수출규정 문서 누락" 한 번에 해결하기 (Feat. 암호화 알고리즘? ) (0) 2024.12.08 [iOS] 상수를 어떻게 관리해야할까 (Feat. struct, enum?) (0) 2024.12.08 [iOS] 최소 지원 버전 (Feat. arm, CPU 아키텍처, 프레임워크 아키텍처) (2) 2024.11.10 [iOS] 디바이스에 데이터 저장하기 1탄 (Feat. UserDefaults) (1) 2024.10.19 [iOS] SwiftUI의 상태 관리 (Feat. @State, @StateObject, @ObservedObject, @Published) (0) 2024.09.22