Closed Larry-Gensch closed 2 years ago
Thanks so much for filing this issue, @Larry-Gensch ! šš¼
You bring up valid concerns. However, these omissions were actually intentional, but I'll be happy to add support (or accept PRs) if there is demand from people who are using this library. š
My reasoning below:
Only Bool, Int, Float, and Double are currently supported numeric types, although UserDefaults can store ANY numeric type that is supported by NSNumber. This includes Int8, Int16, UInt8, UInt16, etc.
The Swift programming guide explicitly discourages the use specific integer sizes, and instead encourages using "plain" Int
. Based on these general language conventions, and the specific context of UserDefaults
, I think it will be very rare that anyone wants to explicitly store something other than Int
.
However, I think there is a case to be made for supporting "plain" UInt
. We should probably do that.
Of course, supporting Int8
, Int16
, etc. is trivial -- I'm curious how many people are actually storing these types in UserDefaults
instead of plain Int
.
The Dictionary support seems to be JSON based [String:: Value.StoredValue]) where UserDefaults actually allows any supported UserDefaults value for a key ([Key.StoredValue: Value.StoredValue])
This isn't true, actually. It's not JSON-based, it's PropertyList-based. Non-string keyed dictionaries are not property list types.
From the Property List Programming Guide, emphasis mine:
If an array or dictionary contains objects that are not property-list objects, then you cannot save and restore the hierarchy of data using the various property-list methods and functions. And although NSDictionary and CFDictionary objects allow their keys to be objects of any type, if the keys are not string objects, the collections are not property-list objects.
Attempting to store a dictionary with non-string keys will throw an exception. I tried. š
Objective-C values that are directly supported by
UserDefaults
are all missing: NSString, NSNumber, NSDictionary, NSArray, etc.
This was also intentional, under the assumption that most people are almost always using Swift types. Again, specifically in the context of UserDefaults
-- if you have a Swift project (even if it's mixed with ObjC) and you want to use a Swift-only feature (this property wrapper), why would you opt for NSNumber
or NSDictionary
when the Swift alternatives are typically a much better choice?
Again, if there's a demand here, I'm happy to add this. But I don't expect there to be a high demand for this...
My mistake regarding Dictionary
. I also accept your comments.
Using NSDictionary
or NSArray
instead of Dictionary
and Array
is sometimes necessary for class semantics for optimal resource storage/retrieval.
@Larry-Gensch no problem! š
sometimes necessary for class semantics for optimal resource storage/retrieval.
I suspect if you are having this problem, the data you are trying to store in UserDefaults
is too large and you should probably be using a database, right?
@jessesquires Can you add support UserDefaultsSerializable to NSColor or can you provide an example of user define type that conform to UserDefaultsSerializable protocol? The doc "Adding support for custom types is possible by conforming to UserDefaultsSerializable" is too little information to me. My use case is : I want to store use customized color settings in UserDefaults.
Thanks.
hey @yujinqiu -- all you need to do is declare conformance to the protocol and implement the methods on your custom type
https://github.com/jessesquires/Foil/blob/main/Sources/UserDefaultsSerializable.swift#L32-L44
struct MyModel: UserDefaultsSerializable {
var storedValue: [Float] {
// todo
}
init(storedValue: [Float]) {
// todo
}
}
Hi @jessesquires thanks for your example for custom type. It works when the MyModel is Struct. But when it comes to NSColor which is Cocoa Class, it failed. I try to give a POC below.
// we cannot add code inside MyModel here directly, NSColor is Cocoa Class
class MyModel {
init() {}
}
extension MyModel: UserDefaultsSerializable {
public var storedValue: MyModel {
return MyModel()
}
public required convenience init(storedValue _: MyModel) {
self.init()
}
}
We'll get Xcode error
'required' initializer must be declared directly in class 'MyModel' (not in an extension)
My current working around is convert NSColor variable to Data Type and save it with Foil, but it's not elegant :-( . Is there any suggestion to store Class type in UserDefaults ?
Hey folks šš¼
I feel like the initial, main concern here has been sufficiently discussed and addressed. I'm going to close this issue.
Feel free to open a new issue for follow-ups! š
Have you read the Contributing Guidelines?
General Information
Project version: 1.0.0
Platform/OS version: iOS 13+
Any related GitHub issues:
Describe the bug
The current implementation of
UserDefaultsSerializable
is too simplistic because it only defines a subset of the values that can be automatically stored inUserDefaults
:Bool
,Int
,Float
, andDouble
are currently supported numeric types, althoughUserDefaults
can store ANY numeric type that is supported byNSNumber
. This includesInt8
,Int16
,UInt8
,UInt16
, etc.String
::Value.StoredValue
]) whereUserDefaults
actually allows any supported UserDefaults value for a key ([Key.StoredValue: Value.StoredValue])UserDefaults
are all missing:NSString
,NSNumber
,NSDictionary
,NSArray
, etc.Steps to reproduce
NA
Expected behavior
Clearly and concisely describe what you expected to happen.
Stack trace, compiler error, code snippets
Example 1 (NSNumber values)
Example 2 (Dictionary)
Screenshots
N/A
Additional context
N/A