-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Implement missing parts of UserDefaults and fix consistency issues #1408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Volatile domains. - UserDefaults.argumentDomain, a particular volatile domain, including arguments parsing. WIP: Requires testing.
- Add persistent domains - Guarantee that all values returned are value types.
@swift-ci Please test. |
Foundation/UserDefaults.swift
Outdated
NotificationCenter.default.post(name: UserDefaults.didChangeNotification, object: self) | ||
_ = defaults.synchronize() | ||
|
||
if removedAny { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This notification is posted unconditionally in the ObjC implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will change.
Foundation/UserDefaults.swift
Outdated
} | ||
} | ||
|
||
open func synchronize() -> Bool { | ||
return CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication) | ||
return CFPreferencesAppSynchronize(suite?._cfObject ?? kCFPreferencesCurrentApplication) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something I did in the ObjC implementation is add CF SPI for “synchronize everything” and call it here, since a ubiquitous pattern of misuse is synchronizing standard user defaults when you set something else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
… ah. hm. I'm inclined to have a follow-up on this one.
while index < count - 1 { // We're looking for pairs, so stop at the second-to-last argument. | ||
let current = arguments[index] | ||
let next = arguments[index + 1] | ||
if current.hasPrefix("-") && !next.hasPrefix("-") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I bet we have subtle unicode behavior handling differences due to Swift string vs NSString, but I don’t think that’s a problem we need to solve here, at least not right now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I can see here, this allows a subset of all defaults we allow on Darwin — namely, we skip all defaults that start with a '-' code point but where that code point forms a grapheme, e.g. '-⃣'. It still allows basically all defaults keys of actual interest, though. But yep.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
… all defaults arguments.
… only fetch values that are objects — it makes a new warning happen on Darwin that I can't silence, but it will work on both platforms and without warnings on Linux.
@swift-ci please test |
…ing this bit of code up.
- Move `_parseArguments` into UserDefaults.swift.
OK, this is ready for review and test (once CI comes back up.) @Catfish-Man @parkera |
@swift-ci please test |
1 similar comment
@swift-ci please test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few review comments, but overall this looks fine
} | ||
return 0 | ||
} | ||
|
||
open func bool(forKey defaultName: String) -> Bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One minor incompatibility between this and what darwin does, which we probably don’t want/need to fix: NSUserDefaults historically coerced values to int/bool/float using different logic from CF. I changed it so that subclasses maintain the old behavior (for compatibility reasons), but un-subclassed NSUserDefaults always uses the CF logic.
I haven’t checked whether this implements the NSUserDefaults version or the CFPrefs version, but I think we should use the CFPrefs behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll double-check. If they're different, there will be a follow-up.
let value = bridgeFromNSCFTypeIfNeeded(nonbridgedValue) | ||
|
||
if let value = value as? [Any] { | ||
for innerValue in value { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The swift tinkerer in me wants to say .lazy.filter { _isValueAllowed($0) }.count > 0, but tbh I’m not sure it’s worth it :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will reply with my standard reply, which is 'if it turns out to be a hot spot'.
Foundation/UserDefaults.swift
Outdated
return _dictionaryRepresentation(searchingOutsideOfSuite: true) | ||
} | ||
|
||
private func _dictionaryRepresentation(searchingOutsideOfSuite: Bool) -> [String: Any] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
searchingOutsideOfSuite seems like a slightly odd name for this. “Suite” is a very fuzzy term in NSUD, but to the extent that it means anything I tend to think of it as referring to a search list, which would generally include registered prefs, etc...
I’m guessing the sense you mean here is “outside of the set of domains matching this identifier”, which is a subset of the search list for that identifier?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup. What about _dictionaryRepresentation(includingOnlySuiteNameDomains:)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We chatted privately and agreed on _dictionaryRepresentation(includingVolatileDomains:)
.
…on Linux; fix them. Fix naming per review.
@swift-ci Please test |
@swift-ci Please test and merge |
This supersedes the patch at #1403.
While implementing persistent domains as a follow-up to volatile domains (and the arguments domain), I've found several issues in UserDefaults that required a whole bit of rethinking of the way this class works. It has been substantially changed.
This patch:
_SwiftValue
instead of trying to do ad-hoc conversions.