Skip to content

Commit d540cce

Browse files
Bharat Medirattaps2
authored andcommitted
Monitor changes and update the widget in real time. (#335)
* Monitor changes and update the widget in real time. Use KVO to watch the UserDefaults object and update the view as appropriate. * Clean up observer implementation 1. call addObserver() in viewDidLoad() 2. call removeObserver() in deinit 3. don't specify options in addObserver() 4. provide a context to the observer code * Move early-return semantics into a guard statement. * Use an explicit, separately named context for observer.
1 parent a3558d4 commit d540cce

File tree

2 files changed

+44
-9
lines changed

2 files changed

+44
-9
lines changed

Loop Status Extension/StatusViewController.swift

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ class StatusViewController: UIViewController, NCWidgetProviding {
1717
@IBOutlet weak var hudView: HUDView!
1818
@IBOutlet weak var subtitleLabel: UILabel!
1919

20+
var statusExtensionContext: StatusExtensionContext?
21+
var defaults: UserDefaults?
22+
final var observationContext = 1
23+
2024
var loopCompletionHUD: LoopCompletionHUDView! {
2125
get {
2226
return hudView.loopCompletionHUD
@@ -54,6 +58,30 @@ class StatusViewController: UIViewController, NCWidgetProviding {
5458

5559
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openLoopApp(_:)))
5660
view.addGestureRecognizer(tapGestureRecognizer)
61+
62+
defaults = UserDefaults(suiteName: Bundle.main.appGroupSuiteName)
63+
if let defaults = defaults {
64+
defaults.addObserver(
65+
self,
66+
forKeyPath: defaults.statusExtensionContextObservableKey,
67+
options: [],
68+
context: &observationContext)
69+
}
70+
}
71+
72+
deinit {
73+
if let defaults = defaults {
74+
defaults.removeObserver(self, forKeyPath: defaults.statusExtensionContextObservableKey, context: &observationContext)
75+
}
76+
}
77+
78+
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
79+
guard context == &observationContext else {
80+
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
81+
return
82+
}
83+
84+
update()
5785
}
5886

5987
override func didReceiveMemoryWarning() {
@@ -67,22 +95,26 @@ class StatusViewController: UIViewController, NCWidgetProviding {
6795
}
6896

6997
func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) {
98+
let result = update()
99+
completionHandler(result)
100+
}
101+
102+
@discardableResult
103+
func update() -> NCUpdateResult {
70104
guard
71-
let context = UserDefaults(suiteName: Bundle.main.appGroupSuiteName)?.statusExtensionContext
105+
let context = defaults?.statusExtensionContext
72106
else {
73-
completionHandler(NCUpdateResult.failed)
74-
return
107+
return NCUpdateResult.failed
75108
}
76-
109+
77110
// We should never have the case where there's glucose values but no preferred
78111
// unit. However, if that case were to happen we might show quantities against
79112
// the wrong units and that could be very harmful. So unless there's a preferred
80113
// unit, assume that none of the rest of the data is reliable.
81114
guard
82115
let preferredUnitString = context.preferredUnitString
83116
else {
84-
completionHandler(NCUpdateResult.failed)
85-
return
117+
return NCUpdateResult.failed
86118
}
87119

88120
if let glucose = context.latestGlucose {
@@ -124,10 +156,9 @@ class StatusViewController: UIViewController, NCWidgetProviding {
124156
} else {
125157
subtitleLabel.alpha = 0
126158
}
127-
159+
128160
// Right now we always act as if there's new data.
129161
// TODO: keep track of data changes and return .noData if necessary
130-
completionHandler(NCUpdateResult.newData)
162+
return NCUpdateResult.newData
131163
}
132-
133164
}

Loop/Extensions/NSUserDefaults+StatusExtension.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ extension UserDefaults {
1414
case StatusExtensionContext = "com.loopkit.Loop.StatusExtensionContext"
1515
}
1616

17+
var statusExtensionContextObservableKey: String {
18+
return Key.StatusExtensionContext.rawValue
19+
}
20+
1721
var statusExtensionContext: StatusExtensionContext? {
1822
get {
1923
if let rawValue = dictionary(forKey: Key.StatusExtensionContext.rawValue) {

0 commit comments

Comments
 (0)