How to create an enum where few cases contains extra properties

Viewed 448

I need 4 file objects to upload. Few files have date, few files have image. What is the data structure should I use?

I tried to create an enum

enum File: String, CaseIterable {
    case a = "A"
    case b = "B"
    case c = "C"
    case d = "D"
    var size: String//enum cannot contain stored properties
}

I tried to create a struct

struct File {
    var name: String//for 4 files
    var size: String//only for A and B
    var image: UIImage// only for C and D
}
4 Answers

This could help you-

    enum File: String, CaseIterable {
    case a = "A"
    case b = "B"
    case c = "C"
    case d = "D"

    static let sizeMapper: [File: String] = [
        .a: "Size A",
        .b: "Size B"
        ]
    static let nameMapper: [File: String] = [
        .a: "Name A",
        .b: "Name B",
        .c: "Name C",
        .d: "Name D"
        ]
    static let imageMapper: [File: UIImage] = [
        .c: UIImage(),
        .d: UIImage()
        ]

    var size: String {
        return File.sizeMapper[self] ?? ""
    }
    var name: String {
        return File.nameMapper[self] ?? ""
    }
    var image: UIImage {
        return File.imageMapper[self] ?? UIImage()
    }
}

call it like this-

        let size = File.a.size
        print(size)
        let name = File.a.name
        print(name)
        let image = File.c.image
        print(image)

The error says it all:

enum cannot contain stored properties

Ideally you're the one to provide values to your enum's properties. Meaning they should be read-only. You can however make a new instance of your enum.

Here's an example:

enum File: String, CaseIterable {
    case a = "A"
    case b = "B"
    case c = "C"
    case d = "D"

    var size: String {
        switch self {
        case .a: return "Some size for A"
        case .b: return "Some size for B"
        case .c: return "Some size for C"
        case .d: return "Some size for D"
        }
    }
}

let fileA = File(rawValue: "A")
let fileB = File(rawValue: "B")

let size = fileA.size //Some size for A
let size = fileB.size //Some size for B

If you answer is "How to create an enum with extra properties", then you can write something like this:

enum File {
   case containingDate(fileName: String, date: Date)
   case containingImage(fileName: String, image: UIImage)
}

Also, note that enum with raw types (in your case it is String) can't contain extra parameters.

PS: to be honest, I don't see any advantages of using enums in your situation

You should use both enum and struct here:

// Enum with associated values for differences
enum FileType {
    case withDate(date: Date)
    case withImage(image: UIImage)
}

// Struct to bind common
struct File {
    var name: String
    var fileType: FileType
}

And then you can have your files defined:

extension File {
    // Files with date
    static let a = File(name: "a", fileType: .withDate(date: Date()))
    static let b = File(name: "b", fileType: .withDate(date: Date()))

    // Files with image
    static let c = File(name: "c", fileType: .withImage(image: UIImage()))
    static let d = File(name: "d", fileType: .withImage(image: UIImage()))
}

And for simple way to access date and image you can declare those handy extensions:

extension FileType {
    var date: Date? {
        if case let .withDate(date) = self {
            return date
        } else {
            return nil
        }
    }

    var image: UIImage? {
        if case let .withImage(image) = self {
            return image
        } else {
            return nil
        }
    }
}

extension File {
    var date: Date? {
        return fileType.date
    }

    var image: UIImage? {
        return fileType.image
    }
}

And then use it like this:

let date = File.a.date
Related