fix: crash on launch in some rare scenarios (closes #615)

This commit is contained in:
Louis Pontoise authored and lwouis committed 2020-09-25 19:15:15 +09:00
1 parent 6803b0232e
commit 5d4b2b0a40
3 files changed
+34 -23

No files matched your search

+1 -1
View File
@@ -19,7 +19,7 @@ class DebugProfile {
("OS architecture", Sysctl.run("hw.machine")),
("Locale", Locale.current.debugDescription),
("Spaces", String(Spaces.allIdsAndIndexes().count)),
("Dark mode", Preferences.getString("AppleInterfaceStyle") ?? "Light"),
("Dark mode", defaults.string(forKey: "AppleInterfaceStyle") ?? "Light"),
("\"Displays have separate Spaces\"", NSScreen.screensHaveSeparateSpaces ? "checked" : "unchecked"),
// hardware
("Hardware model", Sysctl.run("hw.model")),
+26 -15
View File
@@ -151,7 +151,7 @@ class Preferences {
defaults.string(forKey: key)
}
static func set(_ key: String, _ value: Any?) {
static func set(_ key: String, _ value: String) {
defaults.set(value, forKey: key)
UserDefaults.cache.removeValue(forKey: key)
}
@@ -436,39 +436,50 @@ enum CrashPolicyPreference: String, CaseIterable, MacroPreference {
}
extension UserDefaults {
static var cache = [String: Any]()
static var cache = [String: String]()
func getFromCacheOrFresh<T>(_ key: String, _ getterFn: () -> T?) -> T {
func getFromCacheOrFetchAndCache(_ key: String) -> String {
if let c = UserDefaults.cache[key] {
return c as! T
return c
}
if let v = getterFn() {
UserDefaults.cache[key] = v
return v
}
removeObject(forKey: key)
let v = getterFn()!
let v = defaults.string(forKey: key)!
UserDefaults.cache[key] = v
return v
}
func getThenConvertOrReset<T>(_ key: String, _ getterFn: (String) -> T?) -> T {
let stringValue = getFromCacheOrFetchAndCache(key)
if let v = getterFn(stringValue) {
return v
}
removeObject(forKey: key)
UserDefaults.cache.removeValue(forKey: key)
let stringValue2 = getFromCacheOrFetchAndCache(key)
let v = getterFn(stringValue2)!
return v
}
func string(_ key: String) -> String {
return getFromCacheOrFresh(key, { string(forKey: key)! })
return getFromCacheOrFetchAndCache(key)
}
func int(_ key: String) -> Int {
return getFromCacheOrFresh(key, { Int(string(key)) })
return getThenConvertOrReset(key, { s in Int(s) })
}
func bool(_ key: String) -> Bool {
return getFromCacheOrFresh(key, { Bool(string(key)) })
return getThenConvertOrReset(key, { s in Bool(s) })
}
func cgfloat(_ key: String) -> CGFloat {
return getFromCacheOrFresh(key, { Int(string(key)).map { CGFloat($0) } })
return getThenConvertOrReset(key, { s in Int(s).flatMap { CGFloat($0) } })
}
func double(_ key: String) -> Double {
return getThenConvertOrReset(key, { s in Double(s) })
}
func macroPref<A>(_ key: String, _ macroPreferences: [A]) -> A {
return getFromCacheOrFresh(key, { macroPreferences[safe: int(key)] })
return getThenConvertOrReset(key, { s in Int(s).flatMap { macroPreferences[safe: $0] } })
}
}
@@ -18,7 +18,7 @@ class LabelAndControl: NSObject {
static func makeLabelWithCheckbox(_ labelText: String, _ rawName: String, extraAction: ActionClosure? = nil, labelPosition: LabelPosition = .leftWithSeparator) -> [NSView] {
let checkbox = NSButton(checkboxWithTitle: labelPosition == .right ? labelText : " ", target: nil, action: nil)
checkbox.translatesAutoresizingMaskIntoConstraints = false
checkbox.state = (Preferences.getString(rawName)! as NSString).boolValue ? .on : .off
checkbox.state = defaults.bool(rawName) ? .on : .off
let views = makeLabelWithProvidedControl(labelText, rawName, checkbox, labelPosition: labelPosition, extraAction: extraAction)
return views
}
@@ -30,7 +30,7 @@ class LabelAndControl: NSObject {
extraAction?(textArea)
}
textArea.identifier = NSUserInterfaceItemIdentifier(rawName)
textArea.stringValue = Preferences.getString(rawName)!
textArea.stringValue = defaults.string(rawName)
return [textArea]
}
@@ -42,7 +42,7 @@ class LabelAndControl: NSObject {
let popUp = NSPopUpButton()
popUp.translatesAutoresizingMaskIntoConstraints = false
popUp.addItems(withTitles: macroPreferences.map { $0.localizedString })
popUp.selectItem(at: Int(Preferences.getString(rawName)!)!)
popUp.selectItem(at: defaults.int(rawName))
return popUp
}
@@ -56,7 +56,7 @@ class LabelAndControl: NSObject {
return macroPreferences.map {
let button = NSButton(radioButtonWithTitle: $0.localizedString, target: nil, action: nil)
button.translatesAutoresizingMaskIntoConstraints = false
button.state = Int(Preferences.getString(rawName)!)! == i ? .on : .off
button.state = defaults.int(rawName) == i ? .on : .off
_ = setupControl(button, rawName, String(i), extraAction: extraAction)
i += 1
return button
@@ -64,12 +64,12 @@ class LabelAndControl: NSObject {
}
static func makeLabelWithSlider(_ labelText: String, _ rawName: String, _ minValue: Double, _ maxValue: Double, _ numberOfTickMarks: Int, _ allowsTickMarkValuesOnly: Bool, _ unitText: String = "", extraAction: ActionClosure? = nil) -> [NSView] {
let value = Preferences.getString(rawName)!
let suffixText = MeasurementFormatter().string(from: Measurement(value: Double(value)!, unit: Unit(symbol: unitText)))
let value = defaults.double(rawName)
let suffixText = MeasurementFormatter().string(from: Measurement(value: value, unit: Unit(symbol: unitText)))
let slider = NSSlider()
slider.minValue = minValue
slider.maxValue = maxValue
slider.stringValue = value
slider.stringValue = String(value)
slider.isContinuous = true
return makeLabelWithProvidedControl(labelText, rawName, slider, suffixText, extraAction: extraAction)
}