Calendar를 이용한 예약타이머 만들기

Calendar를 이용한 예약타이머 만들기

사내에서, 특정 시간부터 특정 시간까지 앱 스플래시 화면을 변경해야하는 작업이 생겼다.

일반적으로 앱 내에서 Calendar 객체를 이용해 만드는 방법과 서버 드리븐 방법이 있다. 앱 내에서 Calendar 객체를 이용한 경우에는 유저가 디바이스의 시스템 시간 셋팅을 건드리는 경우에 원하는대로 동작하지 않을 수 있다. 그럼에도 불구하고 Calendar로 예약 타이머로 작업하게 되어서 해당 방법을 소개하고자 한다.

주요 포인트는

  • 예약시간을 앱 내에서 관리해야하는 시점에 사방에서 호출하지 않도록 Enum 타입 하나로 관리한다.
  • Manager 객체가 init되는 시점에 from 값 (현재시간), to 값(언제까지 수행되야 하는지에 대한 시간값) 을 받는다.
  • 받은 값을 필요한 시점에 메서드 호출하여 ComparisonResult 타입으로 반환한다.

ReserveDateEnumType

  • case 단위로 관리, case self에 대한 Date타입을 정의한다.
public enum ReserveDateType {
    case splashEvent
    
    public var reserveDate: Date? {
        switch self {
        case .splashEvent:
            return Calendar.current.date(
                from: DateComponents(
                    year: 2023,
                    month: 10,
                    day: 28,
                    hour: 23,
                    minute: 59
                ))
        }
    }
}

ReserveTimeManager

  • init 시점에 toDate는 만들어둔 EnumType으로만 동작하도록 제한한다.
  • 필요한 시점에 compare함수를 호출하여 해당 결과값을 반환
struct ReserveTimeManager {
    private let fromDate: Date
    private let toDate: Date?
    private let granularity: Calendar.Component
    
    init(fromDate: Date, toDate: ReserveDateType, granularity: Calendar.Component? = nil) {
        self.fromDate = fromDate
        self.toDate = toDate.reserveDate
        self.granularity = granularity ?? .minute
    }
    
    func compare() -> ComparisonResult? {
        guard let toDate = self.toDate else { return nil }
        return Calendar.current.compare(fromDate, to: toDate, toGranularity: granularity)
    }
}

ComparisonResult란

  • orderedAscending : 왼쪽 피연산자가 오른쪽 피연산자보다 작다.
  • orderedSame: 왼쪽 피연산자가 오른쪽 피연산자와 동일하다.
  • orderedDescending: 왼쪽 피연산자가 오른쪽 피연산자보다 크다.
/*
 These constants are used to indicate how items in a request are ordered, from the first one given in a method invocation or function call to the last (that is, left to right in code).
 
 Given the function:
   NSComparisonResult f(int a, int b)
 
 If:
    a < b   then return NSOrderedAscending. The left operand is smaller than the right operand.
    a > b   then return NSOrderedDescending. The left operand is greater than the right operand.
    a == b  then return NSOrderedSame. The operands are equal.
*/
@frozen public enum ComparisonResult : Int, @unchecked Sendable {

    
    case orderedAscending = -1

    case orderedSame = 0

    case orderedDescending = 1
}

Date타입을 비교하고 아래와 같이 사용할 수 있다.

let result = CalendarManager(
    fromDate: date,
    toDate: .splashEvent,
    granularity: .month
).compare()

switch result {
case .orderedSame:
    return true
default:
    return false
}