[iOS] Calendar (1)

1 답변 글타래를 보이고 있습니다
  • 글쓴이
    • lidium
      참가자
      • 글작성 : 9
      • 답글작성 : 8

      오늘은 캘린더를 만들어 볼 거예요. 아마도 이번 주와 다음 주.
      안드로이드는 Java의 Calendar 클래스를 이용하면 구현할 수 있는데,
      iOS는 간단한지 어려운지 이번에 알았어요…….
      째끔 간단하면서 어려웠습니다.
      추천 라이브러리 :
      · https://github.com/patchthecode/JTAppleCalendar
      · https://github.com/WenchaoD/FSCalendar

      둘 다 좋아 보입니다. 라이브러리를 적재적소에 사용하는 건 좋은 일입니다.
      시간이 없다면 라이브러리를 적극적으로 채용하도록 합시다.

      이번 사이드 프로젝트의 개인적인 목표 중 하나는… UI Library 없이 앱 만들기였습니다.
      그러자 캘린더를 만들게 되는데…(…)
      일단 한번 만들어보기로 했습니다. 기본적인 구성은 CollectionView로 생각을 하고 있습니다.

      애플에서 기본으로 제공해주는 Calendar Struct를 분석하였습니다.
      기본으로 제공하는 컴포넌트는 다음과 같습니다.

      Calendar.Identifier

      사용하고자 하는 달력의 이름. 일반적으로 그레고리우스 달력입니다 (그레고리력).
      우리가 사용할 달력도 그레고리력입니다. 처음에 세팅을 해 주겠습니다.

      dateComponents

       var firstDayOfTheMonth: Date {
              return Calendar.current.date(from: Calendar.current.dateComponents([.year,.month], from: self))!
          }
      
      let day = ("\(currentYear)-\(currentMonthIndex+1)-01".date?.firstDayOfTheMonth.weekday)!
      

      **

      이 외에도, struct Date에서는 꽤 많은 정보를 제공하고 있습니다. 예를 들어,

      1) Day, 2) Week, 3) Year와 같은 기본적인 정보부터, 4) DateFormatter, 5) 등등 무엇을 제공해 주는지
      공식문서를 꼭 한 번은 정독하고, 정리하는 시간이 필요해 보입니다.
      https://developer.apple.com/documentation/foundation/calendar/2293304-date

      출처 :
      https://github.com/UmairAfzalGitHub/Custom-Calendar-Swift
      https://stackoverflow.com/questions/25533147/get-day-of-week-using-nsdate
      ** day 선언문은 출처를 비롯해서 여러 캘린더 코드에서 사용하였는데, 완벽한 이해가 어렵습니다. 첫 주의 index를 리턴하는 코드입니다.

      ✏️ 초기 달력 세팅

      1 – Calendar.current.component(Calendar.Component, from: <Date>), setupCalendar()

      매개변수의 Calander.current.Component에는 .month, .year, .day 셋 중 하나가 들어갈 수 있습니다.

       currentMonthIndex = Calendar.current.component(.month, from: Date())
      

      주의 애플 캘린더의 month 리턴은 1부터(1 – 12)입니다. 따라서, 평소 하던 대로 배열을 넣으면 어레이 인덱스 에러를 받을 수 있습니다.

      currentMonthIndex -= 1
      

      을 이어지는 줄에 적어 주시고, 다른 부분을 세팅해 주세요.

      setupCalendar()의 코드는 다음과 같습니다.

      func setupCalendar() {
      
              currentMonthIndex = Calendar.current.component(.month, from: Date())
              currentMonthIndex -= 1 // bcz apple calendar returns months starting from 1
      
              currentYear = Calendar.current.component(.year, from: Date())
              todaysDate = Calendar.current.component(.day, from: Date())
      
      
              print("numOfDaysThisMonth : \(numOfDaysInMonth[currentMonthIndex])" )
              print("\ncurrentYear : \(currentYear)")
      
              firstWeekDayOfMonth = getFirstWeekDay()
      
              //for leap years, make february month of 29 days
              if currentYear % 4 == 0 {
                  numOfDaysInMonth[currentMonthIndex] = 29
              }
              //end
              presentMonthIndex = currentMonthIndex
              presentYear = currentYear
      
              // display current month name in title
              topMonthButton.setTitle("\(months[currentMonthIndex]) \(currentYear)", for: .normal)
          }
      

      중간에, 윤년을 체크하는 칸이 있는데
      로직은 어렵지 않게 짜 봤습니다.

      1) 2월의 default는 28일이다.
      2) 마침 올해가 2020년인데 윤년이 있었고, 4년마다 윤년이 돌아오니까?
      3) 그럼 4로 나누면 나머지가 0이네?

      그래서 currentYear % 4 == 0이면 윤년이다라고 알고리즘을 세웠습니다.
      그런데 찾아보니까 1900년 1800년은 다르다 이런 이야기가 나오는데,,,
      저는 2000년도에만 살도록 하겠습니다.

      2 – 매 달 처음 시작하는 요일 계산하기

      DateFormatter()가 필요합니다. 맨 처음에 날짜 세서 7로 나누려고 했는데 잘만 하면 되겠지만, 변수가 많아서
      제공해주는 컴포넌트를 사용해 보겠습니다.

      · DateFormatter()
      – 스트링으로 표현된 Textual Representation과 Date를 변환해주는 객체입니다.
      – 기본적으로 “yyyy-MM-dd” 포맷을 가장 많이 사용합니다. 오늘은 “2020-05-03″이 됩니다.

      예를 들면,

      func getDayOfWeek(_ today:String) -> Int? {
              let formatter  = DateFormatter()    // 1
              formatter.dateFormat = "yyyy-MM-dd" // 2
              guard let todayDate = formatter.date(from: today) else { return nil }  // 3
              let myCalendar = Calendar(identifier: .gregorian)   // 4
              let weekDay = myCalendar.component(.weekday, from: todayDate) // 5
              return weekDay
          }
      
      

      1, 2 –
      DateFormatter() 객체를 선언해서, Format을 yyyy-MM-dd로 선언하였습니다.
      따라서 getDayOfWeek 호출 시 파라미터에는 날짜 형태의 스트링이 필요합니다. (2020-04-25처럼)

      4 –
      아까 맨 위에서 언급한 캘린더의 형태. 우리는 그레고리력을 선택합니다.

      5 –
      이제 리턴을 받을 차례입니다.
      리턴을 받는 숫자는
      요일 : Sun Mon Tue Wed Thr Fri Sat

      숫자 : 1 2 3 4 5 6 7
      입니다! 따라서, 오늘 – 2020-04-25를 입력하면
      7을 리턴해주게 됩니다.

      그럼 우리는 매달 첫 날짜의 Index가 필요하므로, 4월 1일같은 날짜의 인덱스를 만들어내야 합니다.

      ("\(currentYear)-\(currentMonthIndex+1)-01")
      

      currentYear : 현재 날짜
      currentMonthIndex : 현재 월
      -01 : 1일

      합쳐내면 2020-04-01이 됩니다!
      *왜 저는 +1을 했냐라고 물으신다면 아까 setupCalendar()에서 =- 1 해서 배열 index로 쓰느라 그랬습니다….
      *만약 새로 만드실 분들은 그냥 새로 인덱스 한개 파시는게 정신에 이롭습니다.

      이제 UI가 남았는데, UI는 2편에서 계속 만들겠습니다. 감사합니다!😊🎉

    • 야곰
      키 마스터
      • 글작성 : 37
      • 답글작성 : 580

      ㅋㅋ 2000년대에만 사는 심플함 넘 좋네요.

      자바의 Calendar와 애플 환경에서의 Calendar와는 많이 다르죠?ㅎㅎ

1 답변 글타래를 보이고 있습니다
  • 답변은 로그인 후 가능합니다.

logo landscape small

사업자번호 : 743-81-02195
통신판매업 신고번호 : 제 2022-충북청주-1278 호
고객센터 : 카카오톡채널 @yagom