switch statement inside a struct

Hello,

I have this struc containing different information (sensor acquisition mode, sensor location and raw values sent as an array of UInt8). I would like to compute certain properties from raw values depending on the acquisition mode.


I tried different things (mutating function, switch statement) unsucessfully... The switch-case seems to be the neater solution but I can't get it to work, I get a "expected declaration" error message.


Thanks !


enum Location {
    case left, right, up, down
}
enum AcqMode {
    case fast, full
}

struct SensorData {
    var raw: [UInt8]
    var pos: Location
    var mode: AcqMode
    
    init(raw: [UInt8], pos: Location, mode: AcqMode) {
        self.raw   = raw
        self.pos = pos
        self.mode  = mode
    }
    
    switch mode {
    
        case .fast:
            var c1: UInt16 {
                get {
                    return UInt16(raw[0]) * 256 + UInt16(raw[1])
                }
            }
            var c2: UInt16 {
                get {
                    return UInt16(raw[2]) * 256 + UInt16(raw[3])
                }
            }
            var timeStamp: UInt16 {
                get {
                    return UInt16(raw[4]) * 256 + UInt16(raw[5])
                }
            }
    
        case .full:
            var ind:[Int] {
                get {
                    return [Int(raw[0]), Int(raw[1]), Int(raw[2]), Int(raw[3]), Int(raw[4]), Int(raw[5])]
                }
            }
            var timeStamp: UInt16 {
                get {
                    return UInt16(raw[6]) * 256 + UInt16(raw[7])
                }
            }
    }
    
}

It is normal, you write the switch in the declaration "zone", there cannot be instructions here.


I think what you need here is associated values


enum AcqMode {
     case fast(c1:UInt16, c2: UInt16, timeStamp: UInt16)
     case full(ind:[Int], timeStamp: UInt16)
}


You call (in code, not in declaration part):

Assuming acq is an AcqMode


                switch acq {
                case let .fast(c1, c2:, timeStamp):// use c1, c2, timeStamp as needed
                case let .full(ind:, timeStamp):
          }


Note: if you need to modify values, use var instead of let

Look in Swift book for details on how to use associated values.

I would like to compute certain properties from raw values depending on the acquisition mode.

But what properties? Right now your code snippet has the

switch
statement at the declaration level, which is why you’re getting an error. I think you need to introduce a computed properly that accesses the underlying raw values. For example, you might be talking to a sensor where the bottom bit of the first byte represents an ‘overpressure’ flag, which you’d represent as a computed property like this:
struct SensorData {
    var raw: [UInt8]

    var overpressure: Bool {
        get {
            return (raw[0] & 0x01) != 0
        }
        set {
            raw[0] = (raw[0] & 0xfe) | (newValue ? 0x01 : 0x00)
        }
    }
}

Note how I’ve declared the

overpressure
property at the top level and then provided a
get
clause to extract the value from the raw data and a
set
clause to insert it.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for your answer, your code does not work as it is but it got me a bit further:


enum Location {
    case left, right, up, down
}
enum AcqMode {
    case fast, full
}

struct SensorData {
    var raw: [UInt8]
    var pos: Location
    var mode: AcqMode
    
    init(raw: [UInt8], pos: Location, mode: AcqMode) {
        self.raw   = raw
        self.pos = pos
        self.mode  = mode

        switch mode {
            case .fast:
                var c1: UInt16 {
                    get {
                        return UInt16(raw[0]) * 256 + UInt16(raw[1])
                    }
                }
                var c2: UInt16 {
                    get {
                        return UInt16(raw[2]) * 256 + UInt16(raw[3])
                    }
                }
                var timeStamp: UInt16 {
                    get {
                        return UInt16(raw[4]) * 256 + UInt16(raw[5])
                    }
                }
        
            case .full:
                var ind:[Int] {
                    get {
                        return [Int(raw[0]), Int(raw[1]), Int(raw[2]), Int(raw[3]), Int(raw[4]), Int(raw[5])]
                    }
                }
                var timeStamp: UInt16 {
                    get {
                        return UInt16(raw[6]) * 256 + UInt16(raw[7])
                    }
                }
        }
    }
}


in my code:


        let packet: [UInt8] = [0x01, 0x02, 0x03, 0x04, 0x05,0x06, 0x07, 0x08]
        let myObj = SensorData(raw: packet, pos: Location.up, mode: AcqMode.fast)
        let a = myObj.c1


I don't have access to the "getters", the only properties available for myObj are raw, pos and mode, Value of type 'SensorData' has no member 'c1'

Thanks Eskimo, I moved the switch statement after reading Claude31’s response. What you are describing is exactly what I want to do except that I need to find a way to compute the properties depending on the mode selected. My snippet is a simplified version, actually I have 5 different modes and some of them share the same property (e.g. c1) but computed differently. I can’t just write a function, say in a viewController, which would take raw data and mode as parameters because this sensor object is used in several viewControllers and other class. It has to be portable and independent.

It works but it's not pretty


enum Location {
    case left, right, up, down
}
enum AcqMode {
    case fast, full
}

struct SensorData {
    var raw: [UInt8]
    var pos: Location
    var mode: AcqMode
    var c1: UInt16
    var c2: UInt16
    var timeStamp: UInt16
    var ind:[Int]
    
    init(raw: [UInt8], pos: Location, mode: AcqMode) {
        self.raw   = raw
        self.pos = pos
        self.mode  = mode
        self.c1 = 0
        self.c2 = 0
        self.timeStamp = 0
        self.ind = []

        switch mode {
            case .fast:
                self.c1 = UInt16(raw[0]) * 256 + UInt16(raw[1])
                self.c2 = UInt16(raw[2]) * 256 + UInt16(raw[3])
                self.timeStamp = UInt16(raw[4]) * 256 + UInt16(raw[5])
            case .full:
                self.ind = [Int(raw[0]), Int(raw[1]), Int(raw[2]), Int(raw[3]), Int(raw[4]), Int(raw[5])]
                self.timeStamp = UInt16(raw[6]) * 256 + UInt16(raw[7])
        }
    }
}

I fear you misundertsood what I proposed.


Idea, to be able to access to properties was:


enum Location {
    case left, right, up, down
}
enum AcqMode {
    case fast, full
}
enum AcqModeContent {
    case fast(c1:UInt16, c2: UInt16, timeStamp: UInt16)
    case full(ind:[Int], timeStamp: UInt16)
}

struct SensorData {
    var raw: [UInt8]
    var pos: Location
    var modeContent: AcqModeContent
   
    init(raw: [UInt8], pos: Location, mode: AcqMode) { // You init with mode and compute modeContent and store in associated value
        self.raw   = raw
        self.pos = pos
        switch mode {
             case .fast: self.modeContent = AcqModeContent.fast(c1:UInt16(raw[0]) * 256 + UInt16(raw[1]), c2: UInt16(raw[2]) * 256 + UInt16(raw[3]), timeStamp: UInt16(raw[4]) * 256 + UInt16(raw[5]))
             case .full: self.modeContent = AcqModeContent.full(ind: [Int(raw[0]), Int(raw[1]), Int(raw[2]), Int(raw[3]), Int(raw[4]), Int(raw[5])], timeStamp: UInt16(raw[6]) * 256 + UInt16(raw[7]))
        }
    }
}



Then, to call:

        let packet: [UInt8] = [0x01, 0x02, 0x03, 0x04, 0x05,0x06, 0x07, 0x08]
        let myObj = SensorData(raw: packet, pos: Location.up, mode: .fast)
        if case let .fast(c1, c2, timeStamp) = myObj.modeContent {
            print(c1, c2, timeStamp)
        }


Which gives


258 772 1286


It is not very far from what you wrote in fact, but that computes and encapsulates all values in a modeContent property.


Note:

the if case

        if case let .fast(c1, c2, timeStamp) = myObj.modeContent {
            print(c1, c2, timeStamp)
        }

is equivalent to a form that let you analyze all the possible case ; il case let is useful if you search only for one case.

     switch myObj.modeContent {
       case let .fast(c1, c2, timeStamp) : print(c1, c2, timeStamp)
       default : break
      }


If you want to test all cases :

     switch myObj.modeContent {
        case let .fast(c1, c2, timeStamp) : print(c1, c2, timeStamp)
        case let .full(ind, timeStamp) : print("full", ind, timeStamp)
      }
switch statement inside a struct
 
 
Q