들어가기 앞써
안녕하세요 ios 개자이너를 꿈꾸는 콩리또 입니다.
개발은 처음이라 아무것도 모르지만.. Swift 앱 개발에 던져져서 고분분투 하고 있는 중인데요
아직 허접한 실력이지만 나중을 위해 기록을 남기려고합니다...🥹
보시고 더 나은 방법이나 틀린 내용이 있으면 언제든지 댓글 남겨주세요!! 지적 댓글은 늘 환영합니다!
그럼 시작하도록 하겠습니다😀
SwiftUI로 운동 기록 캘린더 만들기
0. 오늘 리뷰할 화면
일단 저는 개발의 "개"자도 모르는 "개린이"이기떄문에 유튜브에 검색해서 나온 동영상을 보고 따라했습니다.
Swift를 잘 아시는 분은 이 유튜브 동영상을 보고 기초틀은 따라하면 될 것 같아요!
근데 이 동영상이 설명이 없는 영상이라... 저는 전혀 이해를 못한 상태에서 따라 쳤는데요...🥹
이제라도 이해해보고자 리뷰를 진행합니다.. 나름 열심히 해석해 봤지만 틀린내용이... 많을 수도 있는점 감안해주세요...
포스팅은 저 같은 Swift 초보자분들이 이해할 수 있도록 저의 눈높이에서 작성될 예정이라 기본적인 내용 많은 점 참고해주세요!
오늘 설명드릴 화면은 아래처럼 기록이 있는 날 캘린더에 이미지가 표시되는 화면입니다!

1. View 만들기
일단 Main.View와 CustomDataPicker 2개의 swift 파일을 만들어주세요
> 파일을 나누는 이유는 재사용할 수 있는 코드가 좋은 코드라 기능별로 파일을 쪼개서 제작하는게 좋다고 하더라고요!
- Main.View : 캘린더(CustomDataPicker)와 AddBtn이 들어갈 예정
- CustomDataPicker : 캘린더

2. 현재 날짜 가져오기
Main.View : 현재 날짜를 가져오는 변수를 선언하고 CustomDataPicker를 불러와주세요.
- Date() : 현재 날짜를 불러올 수 있음. 이때 날짜를 "2022-05-07 00:00:00 +0000" 이런 형식으로 가져오게 되는데, 추후에 DateFormatter()를 사용하면 원하는 형식에 맞게 날짜를 변경할 수 있음
- body에 Vstack를 만들어 CustomDataPicker를 불러옴
struct MainView: View {
@State var currentData: Date = Date()
//Date() = 현재 날짜를 불러옴, 이떄 "2022-05-07 00:00:00 +0000" 이런 형식으로 날짜를 가져옴
var body: some View {
VStack {
CustomDataPicker(currentDate: $currentData)
//CustomDataPicker에 currentDate를 바인딩 할 것이기 때문에 $로 가져옴
}
}
}
CustomDataPicker : MainView에서 선언한 currentDate를 바인딩해서 가져옴
@Binding var currentDate: Date
// MainView에서 선언한 변수를 바인딩해옴
// 바인딩이란? : 변수를 저장해서 가져 오는 것, View와 View끼리의 데이터 연동이 가능!
// A뷰에서 선언한 변수를 바인딩한 B뷰에서 바꿀 경우, A뷰에서도 해당 변수가 변경됨!
3. 현재 월 날짜 가져오기
extension을 사용해 Date 타입에 각 월에 속한 날짜를 가져오는 함수를 추가할거에요
- CustomDataPicker 의 import 아래에(struct 밖) extension을 선언해주세요
extension : 클래스, 구조체, 열거형 혹은 프로토콜 타입에 기능 추가 가능 ( 관련문서(한국어) 보기 )
=> 쉽게 말해, extension을 통해 내가 추가하고 싶은 기능을 넣어 확장(커스텀) 할 때 사용하는 코드라고 생각해주세요!
참고로 extension에는 연산 프로퍼티만 사용 가능! (저장 프로퍼티는 사용불가)
import SwiftUI
extension Date {
//extension + 확장할 타입
}
struct CustomDataPicker: View { ... }
2. 선언한 extension에 getAllDates() 라는 각 월의 날짜를 가져오는 함수를 작성했습니다.
import SwiftUI
extension Date {
func getAllDates() -> [Date] {
//getAllDates = 날짜 타입의 배열로 가져올것
let calendar = Calendar.current
let startDate = calendar.date(from: Calendar.current.dateComponents([.year, .month], from: self))!
//startDate = 캘린더의 년,월 정보를 가져오고 각 월에 해당하는 날짜를 가져오기
let range = calendar.range(of: .day, in: .month, for: startDate)!
//range 사용해 startDate의 월에서 해당 일자를 구하고 벗어나는 날은 nil처리를 해라..?
return range.compactMap { day -> Date in
return calendar.date(byAdding: .day, value: day - 1, to: startDate)!
}
//해석 : startDate의 모든 일자에 -1을 한 값을 리턴해서 nil값이 없는 배열로 만들어라
//compactMap 리턴의 Value: day에 -1해주는거 startDate랑 연관 있는것같은데.. 잘모르겠네욤..ㅎㅎ
}
}
//getAllDates() = 각 월마다의 해당 일자를 가져오고 각 월의 Date 배열을 만들어라
음.... 저는 이렇게 해석을 햇었는데요...
열심히 해석해봤지만 틀린 부분이 있을 수 있습니다... 혹시 있다면 댓글 부탁드려요!!🥹
아무튼 위 코드에서 작성한 메소드들을 설명해드리겠습니다!
★Calendar : 날짜 계산 비교 기능을 제공하는 struct
Calendar.current : 현재 사용하고 있는 달력을 가져옴 (그레고리안 달력)
let calendar = Calendar.current
//Calendar.current는 그레고리안 달력을 의미
calendar.Identifier를 사용하면 다른 형식을 달력도 불러올 수 있어요! ( 관련문서 )
let calendar = Calendar(identifier: .buddhist)
// 불교달력
★.date( from: ) : Calendar 타입에서 사용
date(from: )은 파라미터로 DateComponents 타입을 전달하면 지정한 Components를 토대로 Date?를 리턴해줍니다.
※ ? = 옵셔널, 값이 있을수도 nil일 수도 있다는 뜻이에요!
※ DateComponents 관련내용은 옆의 링크에서 확인하실 수 있어요! (관련문서)
func date(from components: DateComponents) -> Date?
★date( from: ) 사용 예제
저 말만 보면 이해가 되시나요..? 저는 저렇게 글만 보면 이해가 안되기 때문에...
간단한 예제로 예시를 보여드리겠습니다! 설명은 주석을 참고해주세요!
struct calendarTest: View{
let myDateComponents = DateComponents(year: 2022, month: 12, day: 12)
// DateComponents를 이용해 원하는 날짜를 만들 수 있습니다.
let calendar = Calendar.current
// 기준이 되는 달력이 있어야하기 떄문에 claendar도 선언해주세요!
let myDate: Date
// myDateComponents 날짜가 들어갈 변수를 선언
init(){
myDate = calendar.date(from: myDateComponents) ?? Date()
//date(from:)에는 DateComponents 형식을 파라미터로 받기때문에
//위에서 선언해준 myDateComponents을 전달해줄 수 있었습니다!
//근데 swift가 안전성을 추구하기 때문에, 값이 없을떄는 현재 날짜를 전달해주는 코드를 뒤에 써줘야해요!
// ?? : 값이 없을떄(nil 일때) 오른쪽을 실행한다.
}
var body: some View{
Text("\(myDate)")
//myDateComponents에 넣은 날짜(2022.12.12)를 Date 타입으로 불러와줌
}
}

아하! date(from: )는 DateComponents를 넣으면
해당 날짜를 Date 타입으로 만들어주는 메소드인 것을 확인할 수 있습니다!😎
★.range( of: in: for: ) : Calendar 타입에서 사용
range(of: in: for: )는 캘린더에 값을 입력하면 Range<int>? 로 범위를 구해주는 함수입니다!
만약 값이 논리적으로 크지않거나, 구성요소의 조합이 의미가 없는 경우 nil을 반환합니다! (그래서 반환값 뒤에 ?가 붙음)
func range(of: Calendar.Component, in : Calendar.Component, for: Date) -> Range<Int>?
//of : 캘린더의 작은 범위 (예 : day)
//in : of보다 큰 캘린더 범위 (예 : month)
//for : 범위를 구하고 싶은 시간 (Date타입이 들어가야함)
자 일단 여기에서 SwiftUI로 캘린더 만들기 ①편을 마무리 하도록 하겠습니다..
게으른 주제에 완벽을 추구하다보니 글쓰는 시간이 길어져 힘드네요..
보시고 문제 있으신 점은 댓글로 피드백 부탁드립니다!
SwiftUI로 캘린더 만들기 ②편도 기대해주세요~ 만관부><😎
'🍎 IOS > SwiftUI' 카테고리의 다른 글
| SwiftUI 강의 리뷰 - CS193p 2편을 보고... (0) | 2022.05.23 |
|---|---|
| SwiftUI 강의추천 및 리뷰 - Stanford University's course CS193p (6) | 2022.05.17 |