본문 바로가기

iOS

[iOS] Calendar (1)

오늘은 캘린더를 만들어 볼 거예요. 아마도 이번 주와 다음 주.

안드로이드는 Java의 Calendar 클래스를 이용하면 구현할 수 있는데,

iOS는 이렇게 어려운지 이번에 알았어요.......

추천 라이브러리 :

· https://github.com/patchthecode/JTAppleCalendar

 

patchthecode/JTAppleCalendar

The Unofficial Apple iOS Swift Calendar View. Swift calendar Library. iOS calendar Control. 100% Customizable - patchthecode/JTAppleCalendar

github.com

· https://github.com/WenchaoD/FSCalendar

 

WenchaoD/FSCalendar

A fully customizable iOS calendar library, compatible with Objective-C and Swift - WenchaoD/FSCalendar

github.com

둘 다 좋아 보입니다. 라이브러리를 적재적소에 사용하는 건 좋은 일입니다.

시간이 없다면 라이브러리를 적극적으로 채용하도록 합시다.

 

이번 사이드 프로젝트의 개인적인 목표 중 하나는... UI Library 없이 앱 만들기였습니다.

그러자 캘린더를 만들게 되는데...(...)

일단 한번 만들어보기로 했습니다. 기본적인 구성은 CollectionView로 생각을 하고 있습니다.

 

애플에서 기본으로 제공해주는 Calendar Struct를 분석하였습니다.

기본으로 제공하는 컴포넌트는 다음과 같습니다.

Calendar.Identifier 

사용하고자 하는 달력의 이름. 일반적으로 그레고리우스 달력입니다 (그레고리력).

우리가 사용할 달력도 그레고리력입니다. 처음에 세팅을 마쳐주어야 합니다.

dateComponents

  var firstDayOfTheMonth: Date {
        return Calendar.current.date(from: Calendar.current.dateComponents([.year,.month], from: self))!
    }

와 같이 사용합니다. 이제  리턴된 Calendar.current.date으로 사용할 것입니다. ~~~~.firstDayofTheMonth입니다.

이 외에도, 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

 

✏️ 초기 달력 세팅  

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-04-25"가 됩니다.

 

예를 들면,

    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편에서 계속 만들겠습니다. 감사합니다!😊🎉

'iOS' 카테고리의 다른 글

[iOS] SideBar  (3) 2020.05.09
[iOS] Calendar (2)  (0) 2020.05.02
[iOS] LinkPresentation  (0) 2020.04.18
[iOS, Crecker] ActionSheet,  (0) 2020.04.11
[Crecker, iOS] PageViewController (android : ViewPager)  (2) 2020.04.04