Using enumeration type value in Core Data Entity - swift

How to use enumeration type value in Core Data Entity attribute? except choosing transformable.

You can't store the enumeration type directly, because Core Data doesn't understand Swift enums. You'll need to declare the enumeration to have a raw value of some kind, and save the raw value in Core Data. Something like
enum Bar : Int {
case bar1;
case bar2;
}
let myBar = Bar.bar1
// Then save myBar.rawValue in Core Data as an integer type
When reading, get the integer value from Core Data and convert it to the enumeration as
let rawValue = managedObject.bar
let value = Bar(rawValue: rawValue)

Related

CloudKit bytes to array of strings

I have a record on my CloudKit public database that was made via the NSPersistentCloudKitContainer. In Core Data, the attribute is of type [String] and when I add it to the public database, it is converted to Bytes.
When I fetch this record and try to extract the [String] like so
strings = record["CD_strings"] as! [String]
I get the following error:
Could not cast value of type '_NSInlineData' (0x7fe5ae87c2a8) to 'NSArray' (0x7fe5ad835f90).
How are you supposed to get the CKRecordValue as type [String]?
All you need to do is to have the attribute type as transformable, add NSSecureUnarchiveFromData in the transformer field and [String] in Custom Class:

Mapping from string into object parameter

I have a dictionary with an identifier and a value. For example
mappingDictionary["vehicle.fuel_level"] = 50
Now I want to transfer the Dictionary into an object. The object is a rather large object with some child objects.
class Status {
// ...
var vehicle: Vehicle?
// ...
}
class Vehicle {
// ...
var fuel_level: Int?
// ....
}
The naive approach would be to simply make an If query
if dictionary.key = "vehicle.fuel_level" {
statusObject.vehicle.fuel_level = dictionary.value
}
Is there perhaps a generic solution? Using Reflection, I could at least find out where "vehicle.fuel_level" would need to be written. But how do I get a value into an object if you don't know where the value should go?
Is there a kind of "route" to address an object?
Pseudocode:
statusObject["vehicle"].[fuel_level] = dictionary.value
Update:
The data comes from a bluetooth device. The app reads characteristic values. For example the value is just 0,1 or 2. For every characteristic exist a Mapping.
So a bluetooth connector reads values and returns them to an interactor. The interactor calls an interpreter. The interpreter has a mapping config with a type (for example int8, int16, short) and a unit (for example km, percent ...). And this mapping should fill the destination object. So, it would be very nice, when I could say: Put value from string "vehicle.fuel_level" into object vehicle.fuel_level = newValue

Can you define an enum to represent values explicitly known to your app, but still handle unknown values decoded from the backend?

The Problem
Can you define an enum to represent known values for a property in your model while still allowing for unknown values to be returned from the backend?
Short answer: Yes you can! The answer is below.
More Context
As part of our app, we have defined a set of feature flags that the app uses to enable/disable certain features depending on a set of criteria. These flags are sent back from the backend as an array of strings.
However, in our app, rather than dealing with the messiness of string constants, we want to define those values as an enum which we mark as Codable so the compiler handles the encoding/decoding to the actual enum cases for us automatically.
Here's a typical enum for such scenarios...
enum FeatureFlag : String, CaseIterable, Codable {
case allowsTrading
case allowsFundScreener
case allowsFundsTransfer
}
The wrinkle with this design is it doesn't handle values that may be defined, and returned from the backend in the future.
There are several ways to handle this scenario:
Abandon the enum and go to string constants. This is error prone and breaks containment/scoping since any string can participate in this logic.
Stick with an enum as-is and force an update to the app when the backend gets updated passing the buck to deployment.
Update the backend to handle versioning to only return values known to that version of the app complicating the logic on the backend to know about the various front-ends, which they shouldn't.
The most common, defensively program for unknowns by writing your own encoder/decoder methods for each class/struct that uses this enumeration, ignoring any flags not known by the current list of cases.
One through three are maintenance nightmares in their own right. Yes, four is better, but writing all those custom serializers/deserializers can be pretty time-consuming and error-prone, plus it defeats leveraging the benefits of the compiler being able to automatically do it for you!
But what if there's a number five? What if you can make the enumeration itself gracefully handle unknown values at runtime, while remaining lossless in the process, and without having to resort to optionals?
Well that's the exact solution I present below! Enjoy!
TL:DR - The Solution
For those who just want to see the solution, here it is in its entirety. This allows you to define an enum with known cases, but which can handle any raw value thrown at it at runtime, and do so in a lossless way for re-encoding purposes.
enum FeatureFlag : RawRepresentable, CaseIterable, Codable {
typealias RawValue = String
case allowsTrading
case allowsFundScreener
case allowsFundsTransfer
case unknown(RawValue)
static let allCases: AllCases = [
.allowsTrading,
.allowsFundScreener,
.allowsFundsTransfer
]
init(rawValue: RawValue) {
self = Self.allCases.first{ $0.rawValue == rawValue }
?? .unknown(rawValue)
}
var rawValue: RawValue {
switch self {
case .allowsTrading : return "ALLOWS_TRADING"
case .allowsFundScreener : return "ALLOWS_FUND_SCREENER"
case .allowsFundsTransfer : return "ALLOWS_FUNDS_TRANSFER"
case let .unknown(value) : return value
}
}
}
The Explanation
As mentioned above, our app has a certain set of known feature flags. At first, one may define them like so.
enum FeatureFlag : String, CaseIterable, Codable {
case allowsTrading
case allowsFundScreener
case allowsFundsTransfer
}
Simple enough. But again, now any value defined with the type FeatureFlag can only handle one of those specific known types.
Now say thanks to a new feature in the backend, a new flag allowsSavings is defined and pushed down to your app. Unless you have manually written the decoding logic (or resorted to optionals), the decoder will fail.
But what if the enum can handle unknown cases automatically for you, and do so in a completely transparent way?
It can! The trick is to define one additional case, unknown with an associated value of type RawValue. This new case handles all the unknown types handed to it when being decoded or even re-encoded.
Let's start by updating our enum with the new unknown case.
enum FeatureFlag : String, CaseIterable, Codable {
case allowsTrading
case allowsFundScreener
case allowsFundsTransfer
case unknown(RawValue)
}
This of course throws a ton of compiler errors thanks to that new case. Because of it, both RawRepresentable and CaseIterable can no longer be automatically synthesized by the compiler, so we have to manually implement them ourselves. Let's start with...
Manually Implementing the CaseIterable protocol
This is the easiest of the two steps. Since this 'version' of our app only knows about the first three cases, we can safely ignore all others. As such, to satisfy the protocol, we define a static allCases property that only specifies those cases we do care about.
Of Note: The property type AllCases here is an alias for [FeatureFlag] or more succinctly [Self], which we get for free when conforming to CaseIterable.
static let allCases: AllCases = [
.allowsTrading,
.allowsFundScreener,
.allowsFundsTransfer
]
With the above, this satisfies the CaseIterable protocol. Let's move on to...
Manually Implementing the RawRepresentable protocol
This is a little more complex/verbose, but this is where the 'magic' happens.
Specifying the RawValue type
Normally, to indicate your enum can be represented by a raw value, you specify a data type after an enum's name. In actuality, this is shorthand for telling the compiler you are conforming your enum to the RawRepresentable protocol and setting a RawValue typealias for that data type. However, again, because of our unknown type having an associated value, the compiler can't do that implicitly, so we must do so explicitly.
To do so, replace your raw type with RawRepresentable in the definition, then manually set the RawValue typealias inside, like so...
enum FeatureFlag : RawRepresentable, CaseIterable, Codable {
typealias RawValue = String
case allowsTrading
case allowsFundScreener
case allowsFundsTransfer
case unknown(RawValue)
}
implementing the rawValue: property (rawValues matching the case names)
Next up, we have to implement the rawValue property. For known cases where the raw value matches the case name, the implementation is simple as we can just return String(describing: self) and for the unknown cases, we return the associated value. Here's that implementation
var rawValue: RawValue {
switch self {
case let .unknown(value) : return value
default : return String(describing: self)
}
}
implementing the rawValue: property (rawValues unrelated to the case names)
But what if we wanted to express different values from the case names, or even a different data type entirely? In that situation, we have to manually expand out the switch statement and return the appropriate values like so....
var rawValue: RawValue {
switch self {
case .allowsTrading : return "ALLOWS_TRADING"
case .allowsFundScreener : return "ALLOWS_FUND_SCREENER"
case .allowsFundsTransfer : return "ALLOWS_FUNDS_TRANSFER"
case let .unknown(value) : return value
}
}
*Note: You must specify the raw values here and not up with the case definitions using the equals (=) as that's really syntactic sugar for the compiler to create what we're doing manually here, which again we have to since the compiler can't do it for us.
implementing init(rawValue:)... the 'Magic Sauce'
As mentioned, the entire purpose of this exercise is to allow your code to work with known types as usual, but to also gracefully handle unknown cases that are thrown at it. But how do we achieve that?
The trick is in the initializer, you first search for a known type within allCases and if a match is found, you use it. If however a match isn't found, rather than return nil like in the default implementation, you instead use the newly-defined unknown case, placing the unknown raw value inside.
This has the additional benefit of guaranteeing to always return an enum value from the initializer, so we can define it as a non-optional initializer as well (which is different from the implicitly created one from the compiler) making the call-site code easier to use as well.
Here's the implementation of the initializer:
init(rawValue: String) {
self = Self.allCases.first{ $0.rawValue == rawValue }
?? .unknown(rawValue)
}
In some situations, you may want to log when an unknown value is being passed for debugging purposes. That can be done with a simple guard statement (or an if if you prefer) like so...
init(rawValue: String) {
guard let knownCase = Self.allCases.first(where: { $0.rawValue == rawValue }) else {
print("Unrecognized \(FeatureFlag.self): \(rawValue)")
self = .unknown(rawValue)
return
}
self = knownCase
}
Interesting Behaviors on Equality and Hashability
One of the interesting things is that enums based on a raw value actually use that value for equality comparisons. Thanks to that piece of information, all three of these values are equal...
let a = FeatureFlag.allowsTrading // Explicitly setting a known case
let b = FeatureFlag(rawValue: "allowsTrading") // Using the initializer with a raw value from a known case
let c = FeatureFlag.unknown("allowsTrading") // Explicitly setting the 'unknown' case but with a raw value from a known case
print(a == b) // prints 'true'
print(a == c) // prints 'true'
print(b == c) // prints 'true'
Additionally, if your raw value conforms to Hashable, you can make the entire enum conform to Hashable by simply specifying its conformance to that protocol.
extension FeatureFlag : Hashable {}
With that conformance, now you can use it in sets or as keys in a dictionary as well, which again, thanks to the rules of equality above, provides for some interesting, but logically expected, behaviors.
Again, using 'a', 'b' and 'c' as defined above, you can use them like so...
var items = [FeatureFlag: Int]()
items[a] = 42 // Set using a known case
print(items[a] ?? 0) // prints 42 // Read using a known case
print(items[b] ?? 0) // prints 42 // Read using the case created from the initializer with a raw value from the known case
print(items[c] ?? 0) // prints 42 // Read using the 'unknown' case but with a raw value from the known case
Side-Benefit: Lossless Encoding/Decoding
One often-overlooked/underappreciated side-benefit of this approach is that serilization/deserialization is lossless and transparent, even for unknown values. In other words, when your app decodes data containing values you don't know about, the unknown case is still capturing and holding them.
This means if you were to then re-encode/re-serialize that data back out again, those unknown values would be re-written identically to how they would be if your app did know about them.
This is incredibly powerful!
This means for instance if an older version of your app reads in data from a server containing newer, unknown values, even if it has to re-encode that data to push it back out again, the re-encoded data looks exactly the same as if your app did know about those values without having to worry about versioning, etc. They're just silently and happily passed back.
Summary
With the above in place, you can now encode or decode any string into this enumeration type, but still have access to the known cases you care about, all without having to write any custom decoding logic in your model types. And when you do 'know' about the new type, simply add the new case as appropriate and you're good to go!
Enjoy!
Love this proposed solution! One small suggestion, add some logging in case the system encounters unknown types.
init?(rawValue: String) {
if let item = Self.allCases.first(where: { $0.rawValue == rawValue }) {
self = item
} else {
self = Self.other(rawValue)
if #available(iOS 12.0, *) {
os_log(.error, "Unknown FeatureFlag: %s", rawValue)
} else {
print("Error: Unknown FeatureFlag: \(rawValue)")
}
}
}

Swift 5 storing and passing KeyPaths

Let's say I have the following class:
class User: NSObject {
var name = "Fred"
var age = 24
var email = "fred#freddy.com"
var married = false
}
I want to be able to write a generic function that takes in a list of KeyPaths for a known class type, read the values and print to screen. The problem is, the I can't get the following code to compile as the type of the KeyPath's Value is not known, and will be different for each time. What do I have to do to make this work generically?
Consider the following:
struct KeyPathProperties<T> {
var name: String
var relatedKeyPaths: [KeyPath<T, Any>]
}
extension KeyPath where Root == User {
var properties: KeyPathProperties<Root> {
switch self {
case \Root.name:
return KeyPathProperties(name: "name", relatedKeyPaths: [\Root.age, \Root.email])
default:
fatalError("Unknown key path")
}
}
}
This line fails to compile:
return KeyPathProperties(name: "name", relatedKeyPaths: [\Root.age, \Root.email])
with this error:
Cannot convert value of type 'KeyPath<User, Int>' to expected element type 'KeyPath<User, Any>'
This is what I wish to be able to do, for instance:
let myUser = User()
var keyPathProps = KeyPathProperties(name: "name", relatedKeyPaths: [\User.age, \User.email])
for keyPath in props.relatedKeyPaths {
print("Value: \(myUser[keyPath: keyPath])")
}
The above won't compile of course. Essentially I want to store keyPaths in an array at runtime, so I can generically at some point in time get values out of the User. I need to know if I can re-write the above in some way where the compiler can safely and correctly determine the type of the keyPath's value at runtime.
This is a conceptual use case for a much more complex architectural issue I'm trying to solve with hopefully less code.
MORE INFORMATION:
At runtime I wish to keep track of the properties that get modified - these properties are held in a modifiedProps array in each object / instance. At some point at runtime, I wish to be able to enumerate over this array of KeyPaths and print their values like so:
for modifiedKeyPath in self.modifiedProps {
print ("\(self[keyPath: modifiedKeyPath])"
}
In short - I need to be able to capture the generic type of the KeyPath within KeyPathProperties. How do I achieve this?
SIDE NOTE: I can already easily achieve this by using Swift 3 style string based KeyPaths (by adding #objc to the class properties). I can store an array of keyPaths as strings and later do:
let someKeyPath = #keyPath(User.email)
...
myUser.value(forKeyPath: someKeyPath)
I just cannot do this with Swift 4 KeyPaths generically.
The error tells you what your misconception is:
Cannot convert value of type 'KeyPath<User, Int>'
to expected element type 'KeyPath<User, Any>'
You seem to think that you can use a KeyPath<User, Int> where a KeyPath<User, Any> is expected, ostensibly on the grounds that an Int is an Any. But that's not true. These are generic types, and generic types are not covariant — that is, there is no substitution principle for generics based on their parameterized types. The two types are effectively unrelated.
If you need an array of key paths regardless of their parameterized types, you would need an array of PartialKeyPath or AnyKeyPath. It seems that in your use case the root object is the same throughout, so presumably you want PartialKeyPath.

How to compare Associated enums that has no associated value in it

Can I compare associated enum case that has no associated value. Let check the below snippet of code
//Declare associated enum
enum Example
{
case test(x:Int)
case test1(x:String)
}
//Creating enum with associated value
let testWithAssociatedValue = Example.test(x:0)
if case .test = testWithAssociatedValue { //WorksFine
}
//Now having enum with no associated value
let testWithNoAssociatedValue = Example.test
Now Why comparing enum that has no associated value like below,gives me compile error?.
if case .test = testWithNoAssociatedValue {
}
Because Example.test is not an enum case. Try either putting your code in a playground, or checking type(of: Example.test). It will give you (Int) -> Example. That is, under the hood, Example.test behaves like a function that requires an Int and gives you back an Example object. That's why Example.test(x: 10) gives you that enum case.
The notion of "having an associated enum that has no associated value" doesn't make sense. It sounds like you want to make the associated type optional, so you can say Example.test(x: nil).