How to Bind Different Associated Values in a Swift Enum to the Same Var

Can I bind different associated values in a Swift enum to the same var?

That's an interesting case: An enum somehow isn't the right data type, because the value isn't either in radians or in degrees, both are just angles and not really different things. Also typealias Radians = Double wouldn't work because there's no unit safety.

Maybe you can use something like this though:

import Darwin

struct Angle {
enum Unit {
case Radians
case Degrees
case Rotations

var radiansFactor : Double {
switch self {
case Radians: return 1
case Degrees: return 180.0 / M_PI
case Rotations: return 1 / 2 / M_PI
}
}
}

var unit : Unit {
didSet {
value /= oldValue.radiansFactor
value *= unit.radiansFactor
}
}
var value : Double
}

func * (var lhs: Angle, rhs: Double) -> Angle {
lhs.value *= rhs
return lhs
}

var angle = Angle(unit: .Degrees, value: 180)

angle.value // 180.0
angle.unit = .Radians
angle.value // 3.141592...
angle.unit = .Rotations
angle.value // 0.5

Oh and as for the answer to your original question: No you cannot.

Binding to an associated value of an enum

You can extend your enumeration and add a text property with a getter and a setter:

extension Choice {
var text: String {
get {
switch self {
case let .one(string): return string
case let .two(string): return string
}
}
set {
switch self {
case .one: self = .one(newValue)
case .two: self = .two(newValue)
}
}
}
}

Then you can simply pass the text property:

TextField("", text: $choice.text) 

Can I change the Associated values of a enum?

Your most immediate problem is that you're attempting to change the value of an immutable variable (declared with let) when you should be declaring it with var. This won't solve this particular problem though since your name variable contains a copy of the associated value, but in general this is something that you need to be aware of.

If you want to solve this, you need to declare the adjust() function as a mutating function and reassign self on a case by case basis to be a new enum value with an associated value composed from the old one and the new one. For example:

enum SimpleEnum{
case big(String)
case small(String)
case same(String)

mutating func adjust() {
switch self{
case let .big(name):
self = .big(name + "not")
case let .small(name):
self = .small(name + "not")
case let .same(name):
self = .same(name + "not")
}
}
}

var test = SimpleEnum.big("initial")
test.adjust()

switch test {
case let .big(name):
print(name) // prints "initialnot"
case let .small(name):
print(name)
case let .same(name):
print(name)
}

swift enum get the associated value of multiple case with same parameters in single switch-case

You can put multiple enum values in the same case line, but you have to move the let into the ():

var value: Double {
switch self {
case .width(let value), .height(let value), .xxxxx1(let value):
return value
}
}

You might want to put each enum value on a separate line:

var value: Double {
switch self {
case .width(let value),
.height(let value),
.xxxxx1(let value):
return value
}
}

Unfortunately, that's about as elegant as it gets with enums with associated values. There's no way to get the associated value without explicitly listing the enums.

You can only combine values in the same line that have the same type of associated value, and all of the values have to bind to the same variable name. That way, in the code that follows, you know that the value is bound and what its type is no matter which enum pattern matched.

Changing associated value of enum Swift

You can only assign a new enumeration value to the variable.
As in Can I change the Associated values of a enum?,
the associated values of the current values can be retrieved in a switch statement,
with a case pattern which binds the associated value to a local variable.

The currently associated filtered value is not needed, therefore
we can use a wildcard pattern _ at that position.

Since var gameOrigin: Origin? is an optional, we need an “optional pattern” with a trailing question mark.

switch gameOrigin {
case .search(let searchTerm, _)?:
gameOrigin = .search(searchTerm: searchTerm, filtered: filtered)
default:
break
}

The same can be done also in an if-statement with case and pattern
matching:

if case .search(let searchTerm, _)? = gameOrigin {
gameOrigin = .search(searchTerm: searchTerm, filtered: filtered)
}

Binding to an associated value of an enum that has different types of associated values

Indeed, having several very similar properties is a code smell, as well as the fact that those properties were added just because they are needed by the UI layer.

However, since you already have the switch over the value type, you can push the logic for the binding to that (UI) layer. Here's a possible implementation:

struct ValueView: View {
let name: String
@Binding var value: Value

var body: some View {
HStack {
switch value {
case .none:
Spacer()
case let .bool(bool):
Toggle(name, isOn: Binding(get: { bool }, set: { value = .bool($0) } ))
case let .int(int):
Stepper("\(int)", value: Binding(get: { int }, set: { value = .int($0) }))
case let .float(float):
Text(float.description)
case let .string(string):
Text(string)
}
}
}
}

I also took the liberty of extracting the code to a dedicated view and decoupling that view from the Node type, this is more idiomatic in SwiftUI and makes your code more readable and easier to maintain.

With the above in mind, ContentView simply becomes:

Usage:

struct ContentView: View {
@StateObject private var model = Model()

var body: some View {
VStack {
ScrollView {
Text(model.jsonString)
}

List($model.data, id: \.name, children: \.children) { $node in
ValueView(name: node.name, value: $node.value)
}
}
}
}

, and you can safely delete the "duplicated" properties from the Value enum.

Swift - Passing different enum types for same variable to a class

For applying abstraction, you could use protocol, as follows:

protocol Menu {}

enum Menu1: String, Menu {
case option1 = "Option 01 From Menu 01"
case option2 = "Option 02 From Menu 01"
case option3 = "Option 03 From Menu 01"
case option4 = "Option 04 From Menu 01"
case option5 = "Option 05 From Menu 01"
}

enum Menu2: String, Menu {
case option1 = "Option 01 From Menu 02"
case option2 = "Option 02 From Menu 02"
case option3 = "Option 03 From Menu 02"
case option4 = "Option 04 From Menu 02"
case option5 = "Option 05 From Menu 02"
}

By implementing this, you are able to declare arrays of Menu type, which include both of the enums:

let myMenu1Array: [Menu1] = [.option1, .option2, .option5]
let myMenu2Array: [Menu2] = [.option1, .option3, .option4]

For instance, a function that takes a parameter as array of Menus should work:

func handleMenu(_ menuArray: [Menu]) {
if let menu1Array = menuArray as? [Menu1] {
print("Menu 1 Detected!")

// you could iterate through it for instance...
for option in menu1Array {
print(option.rawValue)
}

return
}

if let menu2Array = menuArray as? [Menu2] {
print("Menu 2 Detected!")

// you could iterate through it for instance...
for option in menu2Array {
print(option.rawValue)
}

return
}
}

The output would be:

handleMenu(myMenu1Array)
/*
Menu 1 Detected!
Option 01 From Menu 01
Option 02 From Menu 01
Option 05 From Menu 01
*/

handleMenu(myMenu2Array)
/*
Menu 2 Detected!
Option 01 From Menu 02
Option 03 From Menu 02
Option 04 From Menu 02
*/

So, if you have a property in a class that should represents a menu, you could declare it as a type of Menu:

class  MyClass {
...

var menu: Menu?

...
}

Is it possible to assign multiple values in an enumeration? Swift language

No , enum can't have multiple raw values.But , you can use competed property like that

enum DollarCountries1{
case usa(String?)
var storedDollar : [String] {
["USA","Australia","Canada"]
}

var moneyType : String{
switch self {
case .usa(let str):
if storedDollar.contains(str!){
return "Dollar";
}
return "none"
default:
return "none"
}
}

}

let country = "USA"
var forUsa = DollarCountries1.usa(country)
print(forUsa.moneyType)


Related Topics



Leave a reply



Submit