Swift: Storing states in CoreData with enums - core-data

I want to store an enum state for a managed object within CoreData
enum ObjStatus: Int16 {
case State1 = 0
case State2 = 1
case State3 = 3
}
class StateFullManagedObject: NSManagedObject {
#NSManaged var state: Int16
}
The last step would be converting the state var of StateFullManagedObject to ObjStatus for direct comparison, which isn't working for me. For example, I can't use the == operator between and Int16 and the Int16 enum. The compile time error I get is
Int16 is not convertible to 'MirrorDisposition'
. See the conditional below:
var obj: StateFullManagedObject = // get the object
if (obj.state == ObjStatus.State1) { // Int16 is not convertible to 'MirrorDisposition'
}
How can I compare/assign between an Int16 and an enum?

You can declare your enum as #objc. Then it all automagically works. Here's a snippet from a project I'm working on.
// Defined with #objc to allow it to be used with #NSManaged.
#objc enum AgeType: Int32
{
case Age = 0
case LifeExpectancy = 1
}
/// The age type, either Age or LifeExpectancy.
#NSManaged var ageType: AgeType
In the Core Data model, ageType is set to type Integer 32.

You can extract raw Int16 value with .rawValue property of ObjStatus.
// compare
obj.state == ObjStatus.State1.rawValue
// store
obj.state = ObjStatus.State1.rawValue
But you might want to implement stateEnum accessor for it:
class StateFullManagedObject: NSManagedObject {
#NSManaged var state: Int16
var stateEnum:ObjStatus { // ↓ If self.state is invalid.
get { return ObjStatus(rawValue: self.state) ?? .State1 }
set { self.state = newValue.rawValue }
}
}
// compare
obj.stateEnum == .State1
// store
obj.stateEnum = .State1
// switch
switch obj.stateEnum {
case .State1:
//...
case .State2:
//...
case .State3:
//...
}

Xcode 12.5 Swift 5
I am storing the values of multiple Enums in CoreData with CloudKit Database.
There are quite a few precise steps required to get this working correctly. I have set out here what I have learned works well.
Step 1: Define your Enum:
Mark it #objc, public and Int16
#objc
public enum SomeState: Int16 {
case stateA
case stateB
case stateC
}
Step 2: In your xcdatamodeld create an attribute where the Enum value will be stored
The type should be Integer 16
Step 3: In the Data Model Inspector uncheck Optional, and set a default value of 0
This equates to the first index of the Enum.
Step 4: In the Data Model Inspector for the parent Entity, change Class Codegen to Manual/None
Step 5: Create NSManaged Subclass
Click on the Entity name, then from the menu bar select Editor > Create NSManagedObject Subclass. Make sure that the Target is set to your main project. This will create two new files in the project navigator.
MyObject+CoreDataClass.swift
MyObject+CoreDataProperties.swift
Step 6: In the MyObject+CoreDataProperties.swift file change the attribute type from Int16 to your Enum type
extension MyObject {
#NSManaged public var state: SomeState
}
USAGE:
Setting/updating the value:
myObject.state = .stateA
NSPredicate to search for enum value:
NSPredicate(format: "state = %i", SomeState.stateA.rawValue)

Related

Map complex type to anonymous object

Let's have well known complex type (CT, e.g. Dto from the example).
Let's have set of type converters (functions) transforming value of one type to another (e.g. int SubDto2ToInt(SubDto2 sub), string GuidToString(Guid gd)).
Is there any method, how to configure Automapper and tell him:
"Map CT using these provided Type Converters and create object of anonymous type."?
This would effectively:
go over all CT's properties (recursively)
check the list of converters
if any present for given property type, convert and add to the result
otherwise proceed the default way (put it "as is" to the result)
I have had partial success when I pre-created the anonymous type, but that does not make much sense, because I can then create "normal" target type and define classic mapping. So the point is to let the Automapper create the target type on his own. The target member types would then be driven by either the source type or the conversion result type (if registered).
Example:
class SubDto1 { int M1; int M2; } // Pretend they are get/set properties
class SubDto2 { int N1; int N2; } // dtto
class Dto { SubDto1 Sub1; SubDto2 Sub2; Guid Id; } // dtto
var source = new Dto { Sub1 = new SubDto1 {M1 = 1, M2 = 2}, Sub2 = new SubDto2 {N1 = 10, N2 = 20}, Id = Guid.NewGuid()};
var expectedTargetEquivalentTo = new
{
Sub1 = new {M1 = 1, M1 = 2}, // No conversion registered here, "as is"
Sub2 = 30, // Fancy SubDto2 -> int conversion registered here
Id = "00000000-0000-0000-0000-000000000000", // Guid -> string conversion registered here
}

Typescript: Enforce a type to be "string literal" and not <string>

Problem
Is there a way in Typescript to define a type that is only a string literal, excluding string itself?
Note that I am not talking about a certain list of string literal; for which, a simple union of "Value1" | "Value2", or an enum type would work. I am talking about any string literal, but not string itself.
Example Code
type OnlyStringLiterals = ...; // <--- what should we put here?
const v1: OnlyStringLiterals = "hi"; // should work
const v2: OnlyStringLiterals = "bye"; // should work
// and so should be for any single string value assigned
// But:
const v3: OnlyStringLiterals = ("red" as string); // should NOT work -- it's string
Use Case
I am doing Branding on the types in my code, and I am passing a brand name, as a template, to my parent class. See the code below:
abstract class MyAbstractClass<
BRAND_T extends string,
VALUE_T = string
> {
constructor(private readonly _value: VALUE_T) { }
getValue(): VALUE_T { return this._value; }
private _Brand?: BRAND_T; // required to error on the last line, as intended!
}
class FirstName extends MyAbstractClass<"FirstName"> {
}
class AdminRole extends MyAbstractClass<"AdminRole"> {
}
class SubClassWithMissedName extends MyAbstractClass<string> {
// I want this to error! ........................ ^^^^^^
}
function printName(name: FirstName) {
console.log(name.getValue());
}
const userFirstName = new FirstName("Alex");
const userRole = new AdminRole("Moderator");
printName(userRole); // Already errors, as expected
Playground Link
I want to make sure every subclass is passing exactly a string literal, and not just string to the parent class.
I found an answer that works for my use case, but is not the most reusable one. Just sharing it anyway.
Thought Process
I believe it's not possible to have one solid type to represent what I wanted, because I cannot even think what will show up in VS Code if I hover over it!
However, to my knowledge, there is a function-style checking in Typescript for types that you can pass a type in and expect a type back, and finally assign a value to it to see if it goes through.
Type-checking using a Generic Type and a follow-up assignment
Using this technique I am thinking about the following template type:
type TrueStringLiterals<T extends string> = string extends T ? never : true;
const v1 = "hi";
const check1: TrueStringLiterals<typeof v1> = true; // No error :-)
const v2 = "bye";
const check2: TrueStringLiterals<typeof v2> = true; // No error :-)
const v3 = ("red" as string);
const check3: TrueStringLiterals<typeof v3> = true; // Errors, as expected!
Playground Link
Easier in an already-passed Generic Type
Also, in my use case, I am doing:
abstract class MyAbstractClass<
BRAND_T extends (string extends BRAND_T ? never : string),
VALUE_T = string
> {
...
Playground Link
... which works like a charm!
You can create utility type which will allow only on subset of string:
type SubString<T> = T extends string ?
string extends T ? never
: T
: never
const makeSubStr = <T extends string>(a: SubString<T>) => a
const a = makeSubStr('strLiteral')
const b = makeSubStr('strLiteral' as string) // error
const c: string = 'elo I am string'
const d = makeSubStr(c) // error
const e: SubString<"red"> = ("red" as string); // error
This type will also return never if something is not a string, in your answer TrueStringLiterals will not take this case into consideration and pass it through.
The other answers don't catch the case where the provided type parameter is a union of literal strings. If this shall be explicitly avoided, as could be read from the OPs question, the following solution, based on the other two can be used:
type UnUnion<T, S> = T extends S ? ([S] extends [T] ? T : never) : never;
type NotUnion<T> = UnUnion<T, T>;
type LiteralString<T extends string> = string extends T ? never : NotUnion<T>;
where UnUnion uses the fact that if T is a union, say 'a' | 'b', the union is distributed over the rest of the type expression.
(['a'|'b'] extends ['a'] ? ... ) | (['a'|'b'] extends ['b'] ? ...)
If T is a union, none of these can hold and all the parts turn into never.
NotUnion reduces this to have just one generic parameter and LiteralString just uses its result in case its parameter is not extendable by string.
Playground Link
I'd like to submit an answer from a similar question I recently asked, that is far more simple than the examples given so far:
type SpecificString<S extends Exclude<string, S>> = S
let test1: SpecificString<"a" | "b" | "c"> // okay
let test2: SpecificString<string> // error
//guaranteed to work where `Exclude<string, T>` wouldn't
let test3: Exclude<SpecificString<"a" | "1">, "1">
test3 = "a" // okay
test3 = "1" // error
Basically how this works:
Exclude<string, "any string literal"> ==> resolves to string
Exclude<string, string> ==> resolves to never
You can call this F-bounded quantification if you like I guess.

YamlDotNet SerializationOptions.EmitDefaults behaviour

I'm serializing an object with YamlDotNet with both reference and value types. What i'm looking to accomplish is that my integer values of zero remain in the outputted yaml, but null values would be discarded. EmitDefaults looks to discard '0' for numeric values. i understand null is the default value for reference types. Json.Net solved this with breaking it out into the following properties:
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore,
is there any way to accomplish the below?
class foo
{
int index {get;set;}
string bar {get;set;}
}
new foo { index =0; bar = null }
would yield the following yaml:
index: 0
new foo { index =0; bar = "bar" }
would yield the following yaml:
index: 0
bar: bar
Thanks
Not sure this is what you want, but this is how I force all default values to be serialized:
public override string ToString()
{
var builder = new SerializerBuilder();
builder.EmitDefaults(); // Force even default values to be written, like 0, false.
var serializer = builder.Build();
var strWriter = new StringWriter();
serializer.Serialize(strWriter, this);
return strWriter.ToString();
}

Access String value in enum without using rawValue

I would like to replace my global string constants with a nested enum for the keys I'm using to access columns in a database.
The structure is as follows:
enum DatabaseKeys {
enum User: String {
case Table = "User"
case Username = "username"
...
}
...
}
Each table in the database is an inner enum, with the name of the table being the enum's title. The first case in each enum will be the name of the table, and the following cases are the columns in its table.
To use this, it's pretty simple:
myUser[DatabaseKeys.User.Username.rawValue] = "Johnny"
But I will be using these enums a lot. Having to append .rawValue to every instance will be a pain, and it's not as readable as I'd like it to be. How can I access the String value without having to use rawValue? It'd be great if I can do this:
myUser[DatabaseKeys.User.Username] = "Johnny"
Note that I'm using Swift 2. If there's an even better way to accomplish this I'd love to hear it!
While I didn't find a way to do this using the desired syntax with enums, this is possible using structs.
struct DatabaseKeys {
struct User {
static let identifier = "User"
static let Username = "username"
}
}
To use:
myUser[DatabaseKeys.User.Username] = "Johnny"
Apple uses structs like this for storyboard and row type identifiers in the WatchKit templates.
You can use CustomStringConvertible protocol for this.
From documentation,
String(instance) will work for an instance of any type, returning its
description if the instance happens to be CustomStringConvertible.
Using CustomStringConvertible as a generic constraint, or accessing a
conforming type's description directly, is therefore discouraged.
So, if you conform to this protocol and return your rawValue through the description method, you will be able to use String(Table.User) to get the value.
enum User: String, CustomStringConvertible {
case Table = "User"
case Username = "username"
var description: String {
return self.rawValue
}
}
var myUser = [String: String]()
myUser[String(DatabaseKeys.User.Username)] = "Johnny"
print(myUser) // ["username": "Johnny"]
You can use callAsFunction (New in Swift 5.2) on your enum that conforms to String.
enum KeychainKey: String {
case userId
case email
}
func callAsFunction() -> String {
return self.rawValue
}
usage:
KeychainKey.userId()
You can do this with custom class:
enum Names: String {
case something, thing
}
class CustomData {
subscript(key: Names) -> Any? {
get {
return self.customData[key.rawValue]
}
set(newValue) {
self.customData[key.rawValue] = newValue
}
}
private var customData = [String: Any]()
}
...
let cData = CustomData()
cData[Names.thing] = 56
Edit:
I found an another solution, that working with Swift 3:
enum CustomKey: String {
case one, two, three
}
extension Dictionary where Key: ExpressibleByStringLiteral {
subscript(key: CustomKey) -> Value? {
get {
return self[key.rawValue as! Key]
}
set {
self[key.rawValue as! Key] = newValue
}
}
}
var dict: [String: Any] = [:]
dict[CustomKey.one] = 1
dict["two"] = true
dict[.three] = 3
print(dict["one"]!)
print(dict[CustomKey.two]!)
print(dict[.three]!)
If you are able to use User as dictionary key instead of String (User is Hashable by default) it would be a solution.
If not you should use yours with a nested struct and static variables/constants.

Swift: Convert enum value to String?

Given the following enum:
enum Audience {
case Public
case Friends
case Private
}
How do I get the string "Public" from the audience constant below?
let audience = Audience.Public
The idiomatic interface for 'getting a String' is to use the CustomStringConvertible interface and access the description getter. You could specify the 'raw type' as String but the use of description hides the 'raw type' implementation; avoids string comparisons in switch/case and allows for internationalization, if you so desire. Define your enum as:
enum Foo : CustomStringConvertible {
case Bing
case Bang
case Boom
var description : String {
switch self {
// Use Internationalization, as appropriate.
case .Bing: return "Bing"
case .Bang: return "Bang"
case .Boom: return "Boom"
}
}
}
In action:
> let foo = Foo.Bing
foo: Foo = Bing
> println ("String for 'foo' is \(foo)"
String for 'foo' is Bing
Updated: For Swift >= 2.0, replaced Printable with CustomStringConvertible
Note: Using CustomStringConvertible allows Foo to adopt a different raw type. For example enum Foo : Int, CustomStringConvertible { ... } is possible. This freedom can be useful.
Not sure in which Swift version this feature was added, but right now (Swift 2.1) you only need this code:
enum Audience : String {
case public
case friends
case private
}
let audience = Audience.public.rawValue // "public"
When strings are used for raw values, the implicit value for each case
is the text of that case’s name.
[...]
enum CompassPoint : String {
case north, south, east, west
}
In the example above, CompassPoint.south has an implicit raw value of
"south", and so on.
You access the raw value of an enumeration case with its rawValue
property:
let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection is "west"
Source.
In swift 3, you can use this
var enumValue = Customer.Physics
var str = String(describing: enumValue)
from Swift how to use enum to get string value
For now, I'll redefine the enum as:
enum Audience: String {
case Public = "Public"
case Friends = "Friends"
case Private = "Private"
}
so that I can do:
audience.toRaw() // "Public"
But, isn't this new enum definition redundant? Can I keep the initial enum definition and do something like:
audience.toString() // "Public"
I like to use Printable with Raw Values.
enum Audience: String, Printable {
case Public = "Public"
case Friends = "Friends"
case Private = "Private"
var description: String {
return self.rawValue
}
}
Then we can do:
let audience = Audience.Public.description // audience = "Public"
or
println("The value of Public is \(Audience.Public)")
// Prints "The value of Public is Public"
A swift 3 and above example if using Ints in Enum
public enum ECategory : Int{
case Attraction=0, FP, Food, Restroom, Popcorn, Shop, Service, None;
var description: String {
return String(describing: self)
}
}
let category = ECategory.Attraction
let categoryName = category.description //string Attraction
Updated for the release of Xcode 7 GM. It works as one would hope now--thanks Apple!
enum Rank:Int {
case Ace = 1, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King
}
let r = Rank.Ace
print(r) // prints "Ace"
print("Rank: \(r)!") // prints "Rank: Ace!"
It couldn't get simpler than this in Swift 2 and the latest Xcode 7 (no need to specify enum type, or .rawValue, descriptors etc...)
Updated for Swift 3 and Xcode 8:
enum Audience {
case Public
case Friends
case Private
}
let audience: Audience = .Public // or, let audience = Audience.Public
print(audience) // "Public"
For anyone reading the example in "A Swift Tour" chapter of "The Swift Programming Language" and looking for a way to simplify the simpleDescription() method, converting the enum itself to String by doing String(self) will do it:
enum Rank: Int
{
case Ace = 1 //required otherwise Ace will be 0
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace, .Jack, .Queen, .King:
return String(self).lowercaseString
default:
return String(self.rawValue)
}
}
}
You can also use "\(enumVal)"
Here is an example :
enum WeekDays{ case Sat, Sun, Mon, Tue, Wed, The, Fri }
let dayOfWeek: String = "\(WeekDays.Mon)"
Tried and tested in Swift 5
After try few different ways, i found that if you don't want to use:
let audience = Audience.Public.toRaw()
You can still archive it using a struct
struct Audience {
static let Public = "Public"
static let Friends = "Friends"
static let Private = "Private"
}
then your code:
let audience = Audience.Public
will work as expected. It isn't pretty and there are some downsides because you not using a "enum", you can't use the shortcut only adding .Private neither will work with switch cases.
Starting from Swift 3.0 you can
var str = String(describing: Audience.friends)
Modern, minimalist way
enum Audience: String {
case Public = "Public"
case Friends = "Friends"
case Private = "Private"
func callAsFunction() -> String {
self.rawValue
}
}
let audience = Audience.Public() // "Public"
There are multiple ways to do this. Either you could define a function in the enum which returns the string based on the value of enum type:
enum Audience{
...
func toString()->String{
var a:String
switch self{
case .Public:
a="Public"
case .Friends:
a="Friends"
...
}
return a
}
Or you could can try this:
enum Audience:String{
case Public="Public"
case Friends="Friends"
case Private="Private"
}
And to use it:
var a:Audience=Audience.Public
println(a.toRaw())
Use Ruby way
var public: String = "\(Audience.Public)"
One more way
public enum HTTP{
case get
case put
case delete
case patch
var value: String? {
return String(describing: self)
}
Friendly by guides if you need to use static strings as enum values:
class EncyclopediaOfCats {
struct Constants {
static var playHideAndSeek: String { "Play hide-and-seek" }
static var eat: String { "Eats" }
static var sleep: String { "Sleep" }
static var beCute: String { "Be cute" }
}
}
enum CatLife {
case playHideAndSeek
case eat
case sleep
case beCute
typealias RawValue = String
var rawValue: String {
switch self {
case .playHideAndSeek:
return EncyclopediaOfCats.Constants.playHideAndSeek
case .eat:
return EncyclopediaOfCats.Constants.eat
case .sleep:
return EncyclopediaOfCats.Constants.sleep
case .beCute:
return EncyclopediaOfCats.Constants.beCute
}
}
init?(rawValue: CatLife.RawValue) {
switch rawValue {
case EncyclopediaOfCats.Constants.playHideAndSeek:
self = .playHideAndSeek
case EncyclopediaOfCats.Constants.eat:
self = .eat
case EncyclopediaOfCats.Constants.sleep:
self = .sleep
case EncyclopediaOfCats.Constants.beCute:
self = .beCute
default:
self = .playHideAndSeek
}
}
}
XCode 14.0.1/Swift 5.7:
This is something that should be simple to achieve, but that is quite confusing, with some pitfalls!
Most answers here explain how to associate strings to each enum values, or to create enums of explicit Strings, but is only possible when you are creating your own enums.
In case of enums already existing, like numerous enums in Apple's APIs, one could really want to convert enums values to String.
To take a concrete example, if one wants to display NWConnection.States values in a SwiftUI Text view.
According to some answers, and assuming that we have something like:
Class tcpClient() {
var connection: NWConnection
(...)
then
Text("Current state: \(tcpClient.connection.state)")
should work. But you get a "No exact matches in call to instance method 'appendInterpolation'" error.
A reason to explain this behaviour is because despite being described as enum in Apple's documentation, some enumerations are in fact not Swift enumerations, but C-Style enumerations. And according to Apple, Swift can't print the text version, because all it has at runtime is enum's number value. This could be the case for quite some APIs.
See: https://stackoverflow.com/a/70910402/5965609
Other solution proposed here is:
Text(String(describing: tcpClient.connection.state))
Seems to work, but #Eric Aya comment here says : String(describing:) should never be used to convert anything to String, it's not its purpose and will give unexpected results in many cases. Better use string interpolation or string initializers.
So, in case of C-Style enumarations from APIs or other imported code, the only viable solution seems to have a function with a switch case to associate Strings to each enum's value.
I agree with all the above answers but in your enum private and the public cases can't be defined since those are default keywords. I'm including CaseIterable in my answer, it may help you to get all cases if you required to loop over.
enum Audience: String, CaseIterable {
case publicAudience
case friends
case privateAudience
var description: String {
switch self {
case .publicAudience: return "Public"
case .friends: return "Friends"
case .privateAudience: return "Private"
}
}
static var allAudience: [String] {
return Audience { $0.rawValue }
}
}

Resources