Let say we have an enum with associated value types. In the example below the two value types are simple object that hold an image and a url to share.
enum Content {
  case Image(ShareableImage)
  case Video(ShareableVideo)
}
Now let's have an array of video and image cases.
let media: [Content] = [*a lot of enum cases inside here*]  
All the code above so far cannot be changed in any way in the codebase, I need to work with it.
Here starts my problem:
Let's filter the array with media to only image cases
    let imageOnlyCases: [Content] = media.filter { item -> Bool in
        switch item {
        case .Image: return true
        default: return false
        }
    }
Next step, I want to get from array of enum to an array of their associated values
[Content] -> [ShareableImage] by using map.
so I do this
    let shareablemages = imageOnlyCases.map { imageCase -> ShareableImage in
        switch imageCase {
        case .Image(let image): return image
        default: return  WHAT TO DO HERE?
        }
    }
You see, I have a problem with return type..I know that the enum cases are all .Image..and I want a simple map. But the swift syntax is not helping me.
Any ideas?
You could return image for case .Image, and nil otherwise, within a .flatMap operation (to "filter" out nil entries):
/* Example */
enum Foo {
    case Bar(Int)
    case Baz(Int)
}
let foo: [Foo] = [.Bar(1), .Bar(9),. Baz(3), .Bar(39), .Baz(5)]
/* 1. using 'switch' */
let barOnlyValues: [Int] = foo.flatMap {
    switch $0 {
    case .Bar(let val): return val
    case _: return nil
    }}
/* 2. alternatively, as pointed out in MartinR:s answer; 
      as you're only looking for a single case, the alternative
      'if case let' clause could be preferred over 'switch':     */
let barOnlyValuesAlt: [Int] = foo.flatMap {
    if case let .Bar(val) = $0 { return val }
    else { return nil }}                               
print(barOnlyValues) // [1, 9, 39]
Applied to your use case: note that you needn't perform the filtering to create the imageOnlyCases array, as you can apply the above directly on the media array:
/* 1. using switch */
let shareableImages : [ShareableImage] = media.flatMap {
    switch $0 {
    case .Image(let image): return image
    case _: return nil
    }}
/* 2. 'if case let' alternative, as per MartinR:s suggestion */
let shareableImagesAlt : [ShareableImage] = media.flatMap {
    if case let .Image(image) = $0 { return image }
    else { return nil }}
Disclaimer: I cannot verify your specific use case in practice as I don't have access to the ShareableImage class/struct.
(Thanks @MartinR for advice that .map{ ... }.flatMap{ ... } can be simplified to just .flatMap{ ... }).
If it is guaranteed that only the .Image case can occur then
you can call fatalError() in all other cases:
let shareableImages = imageOnlyCases.map { imageCase -> ShareableImage in
    if case let .Image(image) = imageCase {
        return image
    } else {
        fatalError("Unexpected content")
    }
}
fatalError() causes the program to terminate immediately. It is
only meant for situations that "cannot occur", i.e. to find programming
errors.
It satisfies the compiler because the function is marked as @noreturn.
If you cannot make that guarantee then use flatMap() as suggested
in the other answer.
Note also that you can use if case here with a pattern instead
of switch/case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With