티스토리 뷰
번역이 매끄럽지 못한 점 죄송합니다. 틀린 부분은 댓글로 알려주시면 감사하겠습니다.
원본 : developer.apple.com/documentation/widgetkit/keeping-a-widget-up-to-date
timeline을 통해 위젯을 최신화할 수 있습니다.
위젯은 onscreen상태 일지라도 계속해서 작동하는것이 아닙니다. 위젯은 항상 작동하는 것은 아니지만 최신화 하는 몇 가지 방법이 있습니다.
예측가능한 이벤트를 위한 Timeline 생성하기
위젯은 TimelinePrivider을 통해서 위젯을 업데이트합니다. timeline은 TimelineEntry 객체들의 배열입니다. 각각의 entry는 날짜와 시간을 가지고 있으며 위젯에 표시할 추가적인 정보를 가지고 있습니다. 그리고 위젯이 언제 새로운timeline을 요청할기 알려주는 새로고침 정책을 지정합니다.
아래는 캐릭터의 체력을 나타내는 게임위젯입니다. 캐릭터의 체력이 100% 이하일 때, 캐릭터는 한시간에 25%씩 체력을 회복합니다. 캐릭터 체력이 25%면 100%까지 회복하는데 3시간이 소요됩니다.
위젯이 처음 timeline(타임라인)을 요청했을 때 provider(프로바이더)는 4개의 entries(엔트리, 항목)를 가진 타임라인을 만듭니다. 첫 번째 엔트리는 현재시간을 나타내고 나머지 3개의 엔트리는 1시간 간격으로 나타납니다. 새로고침 정책이 기본값인 atEnd에서 위젯킷은 엔트리의 마지막 시간 뒤에 새로운 타임라인을 요청합니다. 타임라인의 각각의 시간들이 다 도착했을 때 위젯킷은 위젯의 컨텐츠 클로저를 호출하고 결과를 표시합니다.
마지막 타임라인 엔트리가 지나가면 위젯킷은 프로바이더에 새로운 타임라인을 요청하는 과정을 반복합니다. 그 캐릭터의 체력이 100%에 도달했기 때문에 프로바이더는 현재시간의 단일 엔트리에 응답하고 새로고침 정책을 never로 설정합니다. 이 설정으로 위젯킷은 위젯센터에서 다른 요청을 하기 전까지 다른 타임라인을 요청하지 않습니다.
이 부분은 문서에 없지만 추가로 설명을 넣었습니다.
atEnd
정확히 말하자면 atEnd를 했다고 다음 타임라인이 자동으로 .never가 되는 것은 아닙니다.
atEnd 이후에 따로 never를 주지 않으면 계속 업데이트됩니다.
만약에 아래와 같이 타임라인을 만든다면 1분 간격으로 3번만 업데이트 되는 것이 아니라 1분간격으로 3번씩 반복
즉 1분마다 계속해서 위젯을 업데이트합니다.
그리고 제가 테스트를 해본 결과 정확하게 1분간격이 아니라 대략 1분간격이었습니다.
그래서 Text(entry.date, style: .time)로 시간을 표시했을 때
현재 시간이 44분인데 45분으로 표시되기도하고
현재 시간이 48분인데 47분으로 표시되기도 했습니다.
위젯이 업데이트될 시기를 정확하게 알 수는 없습니다.
var entries: [SimpleEntry] = []
let currentDate = Date()
for minOffset in 0..<3 {
let todayList = loadData()
let entryDate = Calendar.current.date(byAdding: .minute, value: minOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate, todayList: todayList)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
프로바이더는 다른 날짜를 지정할 수 있습니다. 예를들어 2시간 후에 용이 나타나고 캐릭터가 전투를 한다면 프로바이더는 새로고침 정책을(_:) 이후로 설정하여 2시간뒤로 전달할 수 있습니다.
용과의 전투로 캐릭터가 회복하는데 2시간이 추가로 필요하게 됩니다. 새로운 타임라인은 현재시간과 2시간뒤의 엔트리로 구성됩니다. 새로고침 정책을 atEnd로 설정해서 더이상 알려진 이벤트가 없음을 표시합니다.
2시간 후에 체력이 100%이 되면 위젯킷은 프로바이더에게 새로운 타임라인을 요청합니다. 캐릭터의 체력이 모두 회복되었기 때문에 프로바이더는 첫번째 사진에서 본 것과 같은 타임라인을 만듭니다. 유저가 게임을 플리에해서 캐릭터의 체력이 떨어지면 위젯센터에서 새로운 타임라인을 새로고침하고 위젯을 업데이트합니다.
프로바이더는 타임라인의 마지막 날짜가 지난후에도 설정가능합니다. 이것은 위젯의 상태가 나중에 변경될 때까지 변경되지 않는다는 것을 알 때 유용합니다. 예를 들어 주식 위젯의 경우 월요일에 개장하는 시간을 나타내는 afterDate() 새로고침 정책을 금요일 시장이 마감되는 시점에 타임라인을 만들 수 있습니다. 왜냐면 주말에는 주식시장이 닫기 때문이고 위젯은 마켓이 열릴때까지 업데이트할 필요가 없기 때문입니다.
위젯킷에 타임라인이 바뀌는것을 알려주기
위젯킷에게 새로운 타임라인을 요청할 수 있습니다. 예를 들어 위에서 말한 게임 위젯의 경우, 친구가 캐릭터에게 체력회복 포션을 줬다는 푸시알림이 떴을 때 타임라인을 불러오고 위젯의 컨텐츠를 업데이트하라고 요청할 수 있습니다. WidgetCenter를 아래와 같이 사용합니다.
WidgetCenter.shared.reloadTimelines(ofKind: "com.mygame.character-detail")
만약에 사용자가 설정하는 속성이 있는 경우 적절한 설정을 가진 위젯이 있는지 확인하기 위해 위젯센터를 사용하여 불필요한 리로드를 피합니다. 예를 들어 체력회복 포션을 받은 캐릭터에 대한 푸시 알림에서 타임라인을 리로드하기전에 위젯이 캐릭터를 보여주고 있는지 확인합니다.
아래 코드에서 getCurrentConfigurations(_:) 를 호출해서 사용자 구성 위젯 목록을 가져옵니다. 그런 다음 결과로 생성된 WidgetInfo 객체를 반복해서 캐릭터가 힐링포션을 받은 인텐트를 찾습니다.
WidgetCenter.shared.getCurrentConfigurations { result in
guard case .success(let widgets) = result else { return }
// Iterate over the WidgetInfo elements to find one that matches
// the character from the push notification.
if let widget = widgets.first(
where: { widget in
let intent = widget.configuration as? SelectCharacterIntent
return intent?.character == characterThatReceivedHealingPotion
}
) {
WidgetCenter.shared.reloadTimelines(ofKind: widget.kind)
}
}
다양한 위젯을 지원하는 위젯번들을 사용하는 경우 한번에 모두 리로드할 수 있습니다.
WidgetCenter.shared.reloadAllTimelines()
동적인 날짜를 표시하기
위젯은 항상 작동하는 것이 아니기 때문에 직접적으로 위젯내용을 업데이트할 수 없습니다. 대신에 위젯킷은 위젯의 뷰를 만들고 결과를 나타냅니다. 그러나 몇몇 SwiftUI 뷰는 위젯이 표시되는 동안 업데이트되는 컨텐츠를 표시하게 할 수 있습니다.
Text뷰를 이용해서 날짜와 시간을 최신화해서 보여줄 수 있습니다.
자동으로 업데이트되는 상대적인 시간 보여주기
let components = DateComponents(minute: 11, second: 14)
let futureDate = Calendar.current.date(byAdding: components, to: Date())!
Text(futureDate, style: .relative)
// Displays:
// 11 min, 14 sec
Text(futureDate, style: .offset)
// Displays:
// -11 minutes
relative 스타일을 사용하면 날짜가 미래인지 과거인지에 관계없이 현재 날짜와 시간과 지정된 날짜의 절대적 차이를 알 수 있습니다. offset스타일은 현재 날짜와 시간과 지정된 날짜의 차이를 나타내며, 마이너스 부호로 미래의 날짜와 플러스 부호로 과거 날짜를 나타냅니다.
자동으로 업데이트하는 타이머 보여주기
let components = DateComponents(minute: 15)
let futureDate = Calendar.current.date(byAdding: components, to: Date())!
Text(futureDate, style: .timer)
// Displays:
// 15:00
미래의 날짜의 경우 timer 스타일은 현재 시간이 지정된 날짜와 시간에 도달할 때까지 카운트다운합니다. 그리고 날짜를 지나면 카운트 업합니다.
절대적인 날짜와 시간 보여주기
// Absolute Date or Time
let components = DateComponents(year: 2020, month: 4, day: 1, hour: 9, minute: 41)
let aprilFirstDate = Calendar.current(components)!
Text(aprilFirstDate, style: .date)
Text("Date: \(aprilFirstDate, style: .date)")
Text("Time: \(aprilFirstDate, style: .time)")
// Displays:
// April 1, 2020
// Date: April 1, 2020
// Time: 9:41AM
두 날짜 사이의 시간 차이 보여주기
let startComponents = DateComponents(hour: 9, minute: 30)
let startDate = Calendar.current.date(from: startComponents)!
let endComponents = DateComponents(hour: 14, minute: 45)
let endDate = Calendar.current.date(from: endComponents)!
Text(startDate ... endDate)
Text("The meeting will take place: \(startDate ... endDate)")
// Displays:
// 9:30AM-2:45PM
// The meeting will take place: 9:30AM-2:45PM
'iOS' 카테고리의 다른 글
[iOS] Xcode Project, Target, Build Settings (0) | 2020.12.28 |
---|---|
[iOS] info.plist란? (0) | 2020.12.28 |
[iOS] prepare segue 데이터 전달, NavigationController segue (0) | 2020.12.01 |
[iOS] TableViewCell CollectionViewCell 재사용 문제 (0) | 2020.11.20 |
[iOS] Swift CollectionViewCell Size 컬렉션뷰 셀 사이즈 (0) | 2020.11.20 |