-
Notifications
You must be signed in to change notification settings - Fork 5
iOS_WidgetKit
์.. ์ฌ๋ฌ๋ถ widget ์ข ๋ง๋ค์ด ๋ณผ๊นํ๋๋ฐ, ์ด๊ฑฐ ๋ง๋ค์๊ณ SwiftUI ๋ฐฐ์ฐ๊ธฐ๊ฐ ์ฐธ ๊ทธ๋ ์ฃ ? ์ฌ์ค ์ UI ์ชฝ ๊ด๋ จํด์๋ง SwiftUI๋ฅผ ์์์ผํ์ง ๋ค๋ฅธ ๋ถ๋ถ์์ ๋ฑํ ๋ชฐ๋ผ๋ ๋๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋ช ํํ ์ฌ์ค์ ์๋์ง๋ง ใ ใ ๐
widget์ ๋ง๋ค๊ธฐ ์ํด์ ํ์์ ์ผ๋ก ์์์ผํ ๊ฒ๋ค์ ์๋ ค๋๋ฆด๊ฒ์
- Provider
- TimelineEntry
- EntryView
์ง์ง ๊ฐ๋ตํ๊ฒ ์ด๋ ๊ฒ 3๊ฐ์ง ๊ตฌ์กฐ์ฒด๊ฐ ์๋๋ฐ, ์ดํดํ๊ธฐ ์ฝ๊ฒ ์ค๋ช ์ ๋๋ฆฌ์๋ฉด,
Provider๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ๋ ๊ตฌ์กฐ์ฒด, TimelineEntry๋ ๋ฐ์ดํฐ ์ ์, EntryView๋ ๊ฐ๊ณต๋ ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ฃผ๋ View
์ด๋ ๊ฒ ์๊ฐํ์๋ฉด ์.. ์ดํดํ๊ธฐ ์ฌ์ฐ์ค ๊ฒ ๊ฐ์์
์ฒซ ๋ฒ์งธ๋ก Provider์ ๋๋ค. ์์ ์ค๋ช ํ๋ฏ์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํด์ฃผ๋ ๊ตฌ์กฐ์ฒด๋ผ๊ณ ๋ง์์ ๋๋ ธ๋๋ฐ, ์ฒ์์ ํ๋ก์ ํธ๋ฅผ ์์ฑํ์๋ฉด ๋งจ ์์ ์๋์ ๊ฐ์ด 3๊ฐ์ง์ ํจ์๊ฐ ์์ฑ๋์ด ์์ ๊ฒ๋๋ค.
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> TimelineEntry {
}
func getSnapshot(in context: Context, completion: @escaping (TimelineEntry) -> ()) {
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
}
}
- placeholder : ์์ ฏ์ด ์ฒ์ ๋์ฌ ๋, ์์ ฏ์ด ๋์ถฉ ์ด๋ ๊ฒ ์๊ฒผ๊ตฌ๋~ ๋ผ๋๊ฑธ ๋ณด์ฌ์ฃผ๊ธฐ ์ํ ๋ฉ์๋
- getSnapshot : ์์ ฏ์ ์ถ๊ฐํ ๋, ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ก ๋ณด์ฌ์ฃผ๊ธฐ ์ํ ๋ฉ์๋
- getTimeline : ์ค์ ํ ์๊ฐ ์ฃผ๊ธฐ๋ง๋ค ๊ฐ๊ณต๋ ๋ฐ์ดํฐ๋ฅผ ๋ทฐ์ ์ ๋ฌํ๊ธฐ ์ํ ๋ฉ์๋
์ด๊ฒ ์ ๊ฐ ์ดํดํ๋๋ก ์ค๋ช ์ ์ ์ด๋ดค๋๋ฐ ํน์๋ผ๋ ์๋ชป๋ ๋ถ๋ถ์ด ์๋ค๋ฉด, ์กฐ์ธ ๋ถํ๋๋ฆฝ๋๋ค ใ ใ ์์ ์ค๋ช ๋๋ก, placeholder์ getSnapshot์ defaultํ ๊ฐ์ ๊ฐ๋จํ๊ฒ ๋ณด์ฌ์ฃผ๊ธฐ ์ํ ๋ฉ์๋๋ผ๊ณ ์๊ฐํ์๋ฉด ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋ง ๊ทธ๋๋ก ์ฝ๊ฐ ์.. ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋๋??
getTimeline์ widget์ ๋ช ๋ถ, ๋๋ ๋ช ์๊ฐ ๋จ์๋ก ์ ๋ฐ์ดํธ ํ ๊ฒ์ธ์ง์ ๋ํด ์ค์ ํ ์ ์๊ณ , ์ด๋ค ๋ฐ์ดํฐ๋ก ์ ๋ฐ์ดํธํ ๊ฒ์ธ์ง๋ ์ค์ ํด์ค ์ ์์ต๋๋ค.
์ ๊ฐ์ ๊ฒฝ์ฐ์, ์ฌ๊ธฐ์ URLSession์ ์ฌ์ฉํ์ฌ API๋ฅผ ํธ์ถํ์ต๋๋ค. ํธ์ถํด์ ์ป์ response๋ก JSON์ ํ์ฑํด์ ๋ฐ์ดํฐ๋ฅผ timelineEntry ๋ผ๋ ๊ตฌ์กฐ์ฒด์ ๋ด์์ completion์ผ๋ก ๋๊ฒจ์ค๋๋ค. ๋๋ต์ ์ธ ์ฝ๋๋ ์๋์ ๊ฐ๊ณ , Timeline์ด๋ผ๋ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง๋ค์ด์ completion์ ๋๊ฒจ์ฃผ๋ ๋ชจ์ต์ ๋๋ค.
์ด ๋ถ๋ถ์์ ์ดํด๊ฐ ์ ์๋ ์๋ ์๋ค๊ณ ์๊ฐํฉ๋๋ค๋ง.. UserInfoEntry๊ฐ ์์์ ๋ง์๋๋ฆฐ timelineEntry๋ฅผ ์ฑํํ ๊ตฌ์กฐ์ฒด๋ผ๊ณ ์๊ฐํ์๋ฉด ๋ ๊ฒ ๊ฐ์ต๋๋ค.
let info = try? JSONDecoder().decode(Response<UserData>.self, from: data)
let entry = UserInfoEntry(date: date, data: info?.data)
completion(Timeline(entries: [entry], policy: .after(nextUpdate)))
์! ์ฌ๋ฌ๋ถ ์ด์ TimelineEntry์ ๋๋ค. ์ฌ์ค์ ์ด๊ฑด ๊ฐ๋จํ ๊ตฌ์กฐ์ฒด์ธ๋ฐ์.. ์.. ๋ชจ๋ธ์ด๋ผ๊ณ ์๊ฐํ์๋ฉด ๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ด๊ธฐ์ ํ๋ก์ ํธ๋ฅผ ์์ฑํ์๋ฉด, ์๋์ ๊ฐ์ด ๊ตฌ์กฐ์ฒด๊ฐ ๋ง๋ค์ด์ ธ ์์ ๊ฒ๋๋ค.
struct ์ฌ๋ฌ๋ถ์ํ๋ก์ ํธ์ด๋ฆentry: TimelineEntry {
let date: Date
}
date๋ ์๋ง ์ ๋ฐ์ดํธ ์์ ์ ์ค์ ํ๊ธฐ ์ํด์? ํ์ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ์์ ๋ง์๋๋ ธ๋ฏ์ด getTimeline ๋ฉ์๋๋ฅผ ํธ์ถํ ๋, ์ ๋ฐ์ดํธ ์์ ์ ์ ํด์ค๋ค๊ณ ํ์ฃ ? ๊ทธ๋์ ํ์ํ ์ ๋ณด๋ผ๊ณ ์๊ฐ์ด ๋ญ๋๋ค. ์ด์ ์ด๊ฑธ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํด์ ์ปค์คํ ํ๋ฉด ๋๋๋ฐ, ์๊ฐ๋ณด๋ค ์ ๋ง ๊ฐ๋จํฉ๋๋ค. ๊ทธ๋ฅ ์ ๊ธฐ๋ค๊ฐ ์ํ๋ ๋ฐ์ดํฐ ํ์ ์ผ๋ก ํ๋กํผํฐ๋ง ์ถ๊ฐ์์ผ์ฃผ๋ฉด ๋์ ๋๋ค. ๐
struct ์ฌ๋ฌ๋ถ์ํ๋ก์ ํธ์ด๋ฆentry: TimelineEntry {
let date: Date
let ์ฌ๋ ค๋ถ์ด์ํ๋๋ฐ์ดํฐ: ์ฌ๋ฌ๋ถ์ด์ํ๋ ๋ฐ์ดํฐํ์
}
์ง์ง ๊ฐ๋จํ์ฃ ? ์ด๋ ๊ฒ ์ค์ ์ ํด๋๊ณ , provider์์ ์ถ๊ฐ๋ ํ๋กํผํฐ์ ๋ง๊ฒ ์ฝ๋๋ฅผ ์กฐ๊ธ์ฉ๋ง ๋ฐ๊ฟ์ฃผ๋ฉด ๋์ ๋๋ค.
๋ง์ง๋ง์ผ๋ก EntryView์ ๋๋ค. ์์์ ๋ฐ์ดํฐํ์ ์ ์ ์ํด์ฃผ๊ณ , ๊ทธ๋ฐ๋ค์ ๊ฐ๊ณต๋ ํด์ฃผ๊ณ .. ๊ทธ ๋ค์์ ์ด์ ๋ฐ์ดํฐ๋ฅผ ๋ทฐ์ ๋ณด์ฌ์ค์ผ๊ฒ ์ฃ ? ์ด๊ฒ๋ ๋ง์ฐฌ๊ฐ์ง๋ก ์ฒ์์ widget ํ๋ก์ ํธ๋ฅผ ์์ฑํ๋ฉด, ์๋์ผ๋ก ์์ฑ๋์ด ์์ต๋๋ค. SwiftUI๋ฅผ ์จ์ผํ๋ค๋ ๊ฑฑ์ ๋๋ฌธ์ ๊ณ์ ๋ฏธ๋ค๋๋ฐ, ์ด๋ ๊ฒ ์น์ ํ๊ฒ ๋ค ํ์ ๋ง๋ค์ด์ค๊ฑฐ๋ผ๊ณค ์๊ฐ๋ ๋ชปํ์ด์ ๐ ์๋์ ๊ฐ์ด ์์ฑ๋์ด ์์ ๊ฒ๋๋ค.
struct Project04WidgetEntryView: View {
var entry: Provider.Entry
var body: some View {
}
}
์ง์ง ๋ค์์ด์ ์ฌ๋ฌ๋ถ ์๊น getTimeline ๋ฉ์๋์์ completion์ผ๋ก Timeline ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง๋ค์ด์ entry๋ฅผ ๋๊ฒจ์คฌ์ฃ ? ์ด๊ฒ ๋ค ์ ๊ธฐ ์ ์ธ๋์ด์๋ entry๋ผ๋ ๋ณ์์ ๋ค์ด๊ฐ ์์ต๋๋ค. ์ ๋ณ์ ์์ ๋ค์ด๊ฐ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ทฐ์๋ค ๋ฟ๋ ค์ฃผ๊ธฐ๋งํ๋ฉด?? ๋์ ๋๋ค. ์ฌ๋ฌ๋ถ ๋ฌผ๋ก ๋ทฐ๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋ถ๋ถ์์๋ SwiftUI์ ๋ํ ํ์ต์ด ํ์ํฉ๋๋ค๋ง.. ์ฌ๊ธฐ์๋ ๋ค๋ฃจ์ง ์๊ฒ ์ต๋๋ค.
ํ๋ฆ์ ๋ํด ์์ฝ์ ํด๋๋ฆฌ์๋ฉด, ์ด์๊ฐ์ ํ๋ฆ์ด๋ผ๊ณ ๋ณด์๋ฉด ๋ ๊ฒ ๊ฐ์ต๋๋ค.
์๋ฒ์์ ๋ฐ์์ฌ ๋ฐ์ดํฐ ํ์ ์ด๋ ๋คํธ์ํฌ๋ฅผ ๋ด๋นํ๋ ๊ฐ์ฒด๋ฅผ ์ด๋ฏธ ๋ฉ์ธํ๋ก์ ํธ์ ๋ง๋ค์ด๋จ๋๋ฐ, widget์์๋ ๋ค๋ฅธ ํ๋ก์ ํธ๋๊น ๋ค์ ํ์ผ์ ์์ฑํด์ผํ๋.. ๋ผ๋ ์๊ฐ์ ์ ๋ ์ฒ์์ ํ์ต๋๋ค. ํ์ง๋ง!! ๊ทธ๋ฅ ๊ฐ๋จํ๊ฒ ์ฌ์ฌ์ฉํ ์ ์๋๋ผ๊ตฌ์.. ใ ใ ์์ฃผ ์ข์ต๋๋ค.
๊ทธ๋ฅ ์ด๋ ๊ฒ ์ฌ์ฌ์ฉํ๊ธธ ์ํ๋ ํ์ผ์ ๊ฐ์ target Membership์ ์ฒดํฌ๋ง ํด์ฃผ๋ฉด ๋ฉ๋๋ค. ๊ฐ๋จํ์ฃ ?
๋น์ฐํ ๊ฐ์ ์ฑ์ด๋๊น UserDefaults๊ฐ ๊ณต์ ๋์ง ์์๊น?? ๋ผ๋ ํฌ๋ง์ฐฌ ์๊ฐ์ ํ์๋๋ฐ, ์ญ์ ์๋์์ด์.. ํ์ง๋ง, ์ฐพ์๋ณด๋ ๋ฐฉ๋ฒ์ด ์๋๋ผ๊ตฌ์! ์ ๋ ์นด!!
์ด๋ฐ ์์ผ๋ก ๊ทธ๋ฃน์ ์ ์ํด์ ์ถ๊ฐ์์ผ์ค๋ค๋ฉด, ๊ทธ๋ฃน๋ผ๋ฆฌ UserDefault๋ฅผ ๊ณต์ ํ ์ ์๋ค๊ณ ํฉ๋๋ค. ๊ทธ๋ฃน์ด๋๊น ๋ฉ์ธํ๋ก์ ํธ์ widgetExtension ๋ ๋ชจ๋ ๊ทธ๋ฃน์ ๋์ผํ ์ด๋ฆ์ผ๋ก ์ค์ ํด์ค์ผ ํฉ๋๋ค.
์ฌ๊ธฐ์ ๋์ด ์๋๋๋ค. ๊ทธ๋ฃน์์ ๊ณต์ ํ๋ UserDefaults๋ฅผ static ๋ณ์๋ก ์ ์ธํด์ค์ผ ํฉ๋๋ค.
extension UserDefaults {
static var shared: UserDefaults {
let appGroupId = "group.namkibeom.project04"
return UserDefaults(suiteName: appGroupId)!
}
}
์๊น ์ค์ ํด์คฌ๋ ๊ทธ๋ฃน์ ์ด๋ฆ์ ๊ทธ๋๋ก ์ฌ์ฉํด์ UserDefaults๋ฅผ ์์ฑํด์ฃผ๊ณ , shared๋ฅผ standard ๋์ ์ฌ์ฉํ๋ฉด ์ ์ฅ๋ ์ ๋ณด๊ฐ ๊ณต์ ๋ฉ๋๋ค.