0

I am trying to set the rawValue of the var VendorIDDeviceID in the below struct.

struct vendor: Codable {
    var VendorIDDeviceID: String

    enum CodingKeys: String, CodingKey {
        case VendorIDDeviceID = "Vendor\(vendorID)Device\(deviceID)"
    }
}

But I need to be able to fill in the variables of vendorID and deviceID during encoding. I have looked an searched the depths of the inter webs and can not find anything that can relate to doing something like this. The closest I have found is:

    let vendorID = "1002"
    let deviceID = "67df"
    let enumCase = vendor.VendorIDDeviceID(rawValue: "Vendor\(vendorID)Device\(deviceID)")

But not seeing how I can implement this during encoding. Any help would be greatly appreciated.

Gereon
  • 17,258
  • 4
  • 42
  • 73
  • 3
    You can't. The error ***Raw value for enum case must be a literal*** is pretty clear, isn't it? – vadian Dec 21 '18 at 22:44
  • yes it is but there has to be some kind of way – Henry Brock Dec 22 '18 at 00:09
  • Using enums and rawValues won't work. Depending on how the JSON you're parsing/generating looks, you might be able to use dynamically generated `CodingKey`s, though. Please post an example. – Gereon Dec 22 '18 at 09:25
  • Not parsing JSON, I'm parsing Plist but here is an example of what I am trying to parse and also setting. https://postimg.cc/dZKVQHTf – Henry Brock Dec 23 '18 at 04:38
  • @Gereon here is an example of what I am trying to parse but I want to change the VendorIDDeviceID section when encoding. https://pastebin.com/raw/LALX2PvV – Henry Brock Jan 05 '19 at 00:31

2 Answers2

0

Here's how I would attempt to parse the JSON from https://pastebin.com/raw/LALX2PvV Since the keys in the MACPro object aren't known in advance, it uses dynamic keys and stores the parsed results in a dictionary.

struct BundleData: Codable {
    let cfBundleName, cfBundleIdentifier, 
        cfBundleInfoDictionaryVersion, osBundleRequired: String
    let cfBundleVersion, cfBundleExecutable, 
        cfBundleGetInfoString, cfBundleSignature: String
    let cfBundlePackageType: String
    let ioKitPersonalities: IOKitPersonalities
    let buildMachineOSBuild, lsMinimumSystemVersion, 
        cfBundleDevelopmentRegion, nsHumanReadableCopyright: String
    let cfBundleShortVersionString: String

    enum CodingKeys: String, CodingKey {
        case cfBundleName = "CFBundleName"
        case cfBundleIdentifier = "CFBundleIdentifier"
        case cfBundleInfoDictionaryVersion = "CFBundleInfoDictionaryVersion"
        case osBundleRequired = "OSBundleRequired"
        case cfBundleVersion = "CFBundleVersion"
        case cfBundleExecutable = "CFBundleExecutable"
        case cfBundleGetInfoString = "CFBundleGetInfoString"
        case cfBundleSignature = "CFBundleSignature"
        case cfBundlePackageType = "CFBundlePackageType"
        case ioKitPersonalities = "IOKitPersonalities"
        case buildMachineOSBuild = "BuildMachineOSBuild"
        case lsMinimumSystemVersion = "LSMinimumSystemVersion"
        case cfBundleDevelopmentRegion = "CFBundleDevelopmentRegion"
        case nsHumanReadableCopyright = "NSHumanReadableCopyright"
        case cfBundleShortVersionString = "CFBundleShortVersionString"
    }
}

struct IOKitPersonalities: Codable {
    let agpm: Agpm

    enum CodingKeys: String, CodingKey {
        case agpm = "AGPM"
    }
}

struct Agpm: Codable {
    let cfBundleIdentifier, ioProviderClass, ioClass: String
    let machines: Machines
    let ioNameMatch: String

    enum CodingKeys: String, CodingKey {
        case cfBundleIdentifier = "CFBundleIdentifier"
        case ioProviderClass = "IOProviderClass"
        case ioClass = "IOClass"
        case machines = "Machines"
        case ioNameMatch = "IONameMatch"
    }
}

struct Machines: Codable {
    let macPro41, macPro51: MACPro

    enum CodingKeys: String, CodingKey {
        case macPro41 = "MacPro4,1"
        case macPro51 = "MacPro5,1"
    }
}

struct MACPro: Codable {
    var defaultControlID: Int
    let devices: [String: DeviceInfo]

    enum CodingKeys: String, CodingKey {
        case defaultControlID = "default-control-id"
    }

    struct DeviceKey: CodingKey {
        var stringValue: String
        var intValue: Int?
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        init?(intValue: Int) {
            self.stringValue = "\(intValue)";
            self.intValue = intValue
        }
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: DeviceKey.self)

        self.defaultControlID = 0
        var devices = [String: DeviceInfo]()
        for key in container.allKeys {
            if let device = try? container.decode(DeviceInfo.self, forKey: key) {
                devices[key.stringValue] = device
            } else if let controlId = try? container.decode(Int.self, forKey: key) {
                self.defaultControlID = controlId
            }
        }

        self.devices = devices
    }
}

struct DeviceInfo: Codable {
    let heuristic: Heuristic
    let logControl, controlID: Int

    enum CodingKeys: String, CodingKey {
        case heuristic = "Heuristic"
        case logControl = "LogControl"
        case controlID = "control-id"
    }
}

struct Heuristic: Codable {
    let thresholdLow: [Int]
    let idleInterval, sensorSampleRate, targetCount, sensorOption: Int
    let thresholdHigh: [Int]
    let id: Int

    enum CodingKeys: String, CodingKey {
        case thresholdLow = "Threshold_Low"
        case idleInterval = "IdleInterval"
        case sensorSampleRate = "SensorSampleRate"
        case targetCount = "TargetCount"
        case sensorOption = "SensorOption"
        case thresholdHigh = "Threshold_High"
        case id = "ID"
    }
}

let data = json.data(using: .utf8)!
do {
    let bundleData = try JSONDecoder().decode(BundleData.self, from: data)
    print(bundleData)
}
catch {
    print(error)
}
Gereon
  • 17,258
  • 4
  • 42
  • 73
0

The CustomCodingKeys explained here also works for encoding: https://stackoverflow.com/a/50715560/6324550

public struct Schedule: Codable {
    public let periods: Periods
}

public struct Periods: Codable {
    public var innerArray: [String: [Inner]]

public struct Inner: Codable {
    public let firstName: String
    public let lastName: String
}

private struct CustomCodingKeys: CodingKey {
    var stringValue: String
    init?(stringValue: String) {
        self.stringValue = stringValue
    }
    var intValue: Int?
    init?(intValue: Int) {
        return nil
    }
}
public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CustomCodingKeys.self)

    self.innerArray = [String: [Inner]]()
    for key in container.allKeys {
        let value = try container.decode([Inner].self, forKey: CustomCodingKeys(stringValue: key.stringValue)!)
        self.innerArray[key.stringValue] = value
    }
}
Cyberbeni
  • 660
  • 4
  • 15