ABOUT ME

작은 디테일에 집착하는 개발자

Today
-
Yesterday
-
Total
-
  • [iOS] Swift에서 날짜 기반 채팅 목록 그룹화 개선하기 (Feat. 그룹화 우선순위의 오류, sortWeight)
    IT Study/iOS 2025. 1. 30. 17:01
    728x90

    "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월"의 정렬만 봤기에 지금까지는 문제가 없는 줄 알았습니다. 지금까지의 방식은 아래와 같은 문제가 생길 수 있습니다.

    1. "오늘", "어제" 등 문자표기가 들어오면 사전순과 의도한 순서가 엇갈릴 수 있다는 것.
    2. 한글, 숫자, 연도("2024년")를 단순 문자열로 정렬하면 예기치 못한 순서가 만들어진다는 것.
    3. 결국 2025년 1월과 2024년이 서로 정확히 어떤 순서로 비교되어야 하는지, 문자열 비교만으로는 해결할 수 없다는 것.

     


     

    3. 해결 방법: 그룹 우선순위 + 정렬된 배열 의 반환

    제가 원하는 건 "오늘 → 어제 → 올해(월 순서) → 이전 연도(연 순서)" 정렬입니다. 이를 위해 sortWeight(우선순위)를 부여해 "그룹별" 정렬 기준을 명확히 하고, 그 결과를 기존 Dictionary 대신, 이미 정렬된 배열의 형태로 만들어서 UI에 넘기면 됩니다. (그리고 UI에서는 배열 그대로 사용하면 되죠.)

    1. sortWeight 도입
      • 오늘 (3) > 어제 (2) > 현재 연도 월별 (1) > 이전 연도 (0)
      • 같은 우선순위 내에서는 날짜 내림차순으로 정렬 (예: 2월 > 1월)
    2. 최종 반환은 [(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: >) 같은 코드 쓰고 계신다면… 한 번쯤 다시 생각해보시길!🔥)

     

    후련하게 해결한 사진까지 투척...

Designed by Tistory.