This question already has answers here:
Swift enum inheritance
(3 answers)
Closed 3 years ago.
I am trying to create an inheritance for below enum
enum BankAuthError: String {
case authFailed = "AuthFailed"
case technicalError = "Unavailable"
case accountLocked = "Locked"
case unknownError = "UnknownError"
case userInteractionRequired = "UserInteractionNeeded"
case realmUserAlreadyConnected = "UserExists"
}
I am able to use this enum as below
let errorCode = BankAuthError(rawValue:errorMessageCodeString)
Now I am trying to create inheritance from above struct as below
//MARK:- Enum to handle all sysnc errors
enum SyncErrorStatus: BankAuthError {
case usernameOrPasswordMissing = "UsernameOrPasswordMissing"
case signatureMissing = "SignatureMissing"
case twoPhaseAuthentication = "TwoPhaseAuth"
}
But if I am doing this, I am getting the compiler error as
'SyncErrorStatus' declares raw type 'BankAuthError', but does not
conform to RawRepresentable and conformance could not be synthesized
Please let me know whether can we create inheritance from above Raw enum or not.
Enums are value types, so there's no such thing as inheritance for enums. When you declare an enum as enum YourEnum: Type, you declare the rawValue of your enum to be of type Type. However, Type needs to conform to RawRepresentable.
What you are looking for, to create an enum that contains all cases of another enum, plus some other cases in currently not possible in Swift. You cannot inherit all cases of an enum.
Related
just curious about something.
private enum CodingKeys: String, CodingKey {
case id = "page"
}
If I were to place String after the CodingKey protocol I would get an error saying I need to place String before.. well what determines the priority and why does that even matter? Thanks in advance.
Protocol conformance order does not matter. In your case you are getting an error when you place String after CodingKey is because String is not a protocol. It is a struct. Look at the error message what you get in Xcode:
Raw type 'String' must appear first in the enum inheritance clause
By placing String after the enum declaration will define its raw value.
To prove the point let's define two protocols:
protocol Protocol1 { }
protocol Protocol2 { }
And try to change the order they conform to your CodingKeys enum. This would be valid:
private enum CodingKeys: String, CodingKey, Protocol1, Protocol2 {
case id = "page"
}
And this is valid too:
private enum CodingKeys: String, CodingKey, Protocol2, Protocol1 {
case id = "page"
}
It’s a language requirement that for a declaration of Enumerations with Cases of a Raw-Value Type the raw-value type must come before any adopted protocol.
See https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID364
I have an enum that looks like this:
enum IntteruptCause: UInt8 {
case userDisplayDisengage = 0
case userSteeringWheelDisengage = 1
case positionDropout = 2
}
Currently the output from print() will give me the case name.
I would like to implment CustomStringConvertible and have it produce both the case name and the rawValue, e.g. the string User_Steering_Wheel_Disengage (1).
When I implement var description: String I have easy access to rawValue but I cannot seem to find out how to get the enum case name. Normally I would do String(describing: value) but that would create an infinite recursion if used in description implementation.
Is it possible to get the enum case name from within the description implementation?
Background
I have an enum which, simplified, goes like this:
enum Container<T> {
case a(T)
case b(T)
case c
}
I want to be able to instantiate this with a few different types for the generic and use typealias for that:
typealias IntContainer = Container<Int>
typealias FloatContainer = Container<Float>
Problem
So far, this is all fine. However, I also want to create a recursive instance of this:
typealias CyclicContainer = Container<CyclicContainer>
Swift reports this with a compile error:
Type alias 'CyclicContainer' references itself
… This error is still reported when I change the Container declaration to:
indirect enum Container<T>
This is a bit annoying, because this would be wholesome and compiling Swift:
indirect enum CyclicContainer {
case a(CyclicContainer)
case b(CyclicContainer)
case c
}
Workaround 1
There is a work around for this. I can declare, for example:
indirect enum CyclicContainer {
case container(Container<CyclicContainer>)
}
… However, this becomes awkward for concise descriptions of a CyclicContainer instance:
let cyclicContainer: CyclicContainer = .container(.a(.container(.b(.container(.c)))))
Instead of just:
let cyclicContainer: CyclicContainer = .a(.b(.c))
Workaround 2
I could also simply create a separate enum for the recursive case, as shown earlier:
indirect enum CyclicContainer {
case a(CyclicContainer)
case b(CyclicContainer)
case c
}
However, I'll need to: create functions to convert between CyclicContainer and Container; re-implement various member functions that exist on Container<T>; and keep the two types in sync in future if I add a new case or change a case name.
This isn't terribly arduous and it's the approach I'm leaning towards. But it seems a shame to have to do this when Swift can handle an indirect enum completely happily, but not when its induced by instantiation of a generic argument on the enum.
Question
Is there a better way?
I am very new to Swift. Is there a generic all-encompassing Object class in Swift like there is in Java/C#?
Can I declare an array that can hold anything (Int/String/Character...etc)?
As explained in "Why is there no universal base class in Swift?", no, but there is a common protocol that every type implicitly conforms to: Any.
// A statically typed `Any` constant, that points to a value which
// has a runtime type of `Int`
let something: Any = 5
// An array of `Any` things
let things: [Any] = [1, "string", false]
for thing in things {
switch thing {
case let i as Int: consumeInt(i)
case let s as String: consumeString(s)
case let b as Bool: consumeBool(b)
// Because `Any` really does mean ANY type, the compiler can't prove
// that this switch is exhaustive, unless we have a `default`
default: fatalError("Got an unexpected type!")
}
}
However, using Any is ill-advised most of the time. For most purposes, discriminated unions are a better choice, which Swift has in the form of enums. These ensure that all possible types are considered:
// Using an enum with associated values creates a discriminated union
// containing the exact set of type that we wish to support, rather than `Any`
enum SomeValue { // Note: this is a bad name, but just as an example!
case int(Int)
case string(String)
case bool(Bool)
}
let someValues: [SomeValue] = [.int(1), .string("string"), .bool(false)]
for value in someValues {
switch value {
case .int(let i): consumeInt(i)
case .string(let s): consumeString(s)
case .bool(let b): consumeBool(b)
// Enums have finitely many cases, all of which we exhausted here
// No `default` case required!
}
}
There are Anyand AnyObject types that are seem to what you search for. You can't extend them but you can up cast any object to AnyObject type and insert into [AnyObject] array. Any is more wide, and includes Int, String, Bool, etc.
No, Swift does not have a generic Object Class.
Is it possible to use a List to store an array of enum values? The compiler doesn't complain if I include RealmCollectionValue in the enum definition, but I'm not convinced this is supported since the supported primitive types include extensions with a function func _rlmArray() -> RLMArray<AnyObject> and I'm not sure how the rawValue figures into this.
For example:
enum AlarmOffset: Int, RealmCollectionValue {
case dayOfEvent = 0
case oneDay = -1
case twoDays = -2
case sevenDays = -7
case thirtyDays = -30
}
class UserPreferences: Object {
#objc dynamic var id: String = UUID().uuidString
let alarmOffsets = List<AlarmOffset>()
}
As of Realm Swift v10.10.0, you can declare any RawRepresentable enum as conforming to PersistableEnum and use it as a property type on Realm objects and inside Realm collections. Note that this requires using #Persisted and not the legacy obj-c declaration syntax.
This almost works by coincidence, but declaring your own types as conforming to RealmCollectionValue currently isn't supported. The types which can be stored in a Realm collection are annotated with that protocol, but implementing that protocol is not sufficient to make it possible to store a type in a Realm collection.