Enum associated value confusing

105 Views Asked by At

When I try use func obj func, I get the error:

Cannot invoke 'obj' with an argument list of type '(message: (QueueAddable))'

I'm confused with Swift types. Obj func used to get concrete type for decode.

protocol QueueAddable: Encodable {
    var playlistsCollection:String? { get }
    var playlists: [String]? { get }
}

struct Playlist: QueueAddable {
    var playlistsCollection:String? {
        return "id"
    }
    var playlists: [String]? {
        return ["id", "id2"]
    }
    private enum CodingKeys:String,CodingKey {
        case playlistsCollection
        case playlists
    }

    public func encode(to encoder: Encoder) throws {
        var values = encoder.container(keyedBy: CodingKeys.self)
        try values.encode(playlistsCollection, forKey: Playlist.CodingKeys.playlistsCollection)
        try values.encode(playlists, forKey: .playlists)
    }
}

func obj<Q>(message: Q) where Q: QueueAddable {
    let encoder = JSONEncoder()
    let data = try! encoder.encode(message)
}

enum SomeEnum {
    case playlist(QueueAddable)
    func doSome() throws -> Data {
        switch self {
        case .playlist(let queueAddable):
            let encoder = JSONEncoder()

            // Error on the following line:
            obj(message: queueAddable)
            return Data()
        }
    }
}

let playlist = Playlist()
let data = try SomeEnum.playlist(playlist).doSome()
1

There are 1 best solutions below

0
On BEST ANSWER

I think the problem is that the function expects a type and not a protocol. If you make the enum generic using a type that implements the protocol it will work.

Change the enum's first two lines like this:

enum SomeEnum<Q : QueueAddable> {
case playlist(Q)

I tested in the following playground:

import Foundation

protocol QueueAddable: Encodable {
    var playlistsCollection:String? { get }
    var playlists: [String]? { get }
}

struct Playlist: QueueAddable {
    var playlistsCollection:String? {
        return "id"
    }
    var playlists: [String]? {
        return ["id", "id2"]
    }
    private enum CodingKeys:String,CodingKey {
        case playlistsCollection
        case playlists
    }

    public func encode(to encoder: Encoder) throws {
        var values = encoder.container(keyedBy: CodingKeys.self)
        try values.encode(playlistsCollection, forKey:      Playlist.CodingKeys.playlistsCollection)
        try values.encode(playlists, forKey: .playlists)
    }
}

func obj<Q>(message: Q) where Q: QueueAddable {
    let encoder = JSONEncoder()
    let data = try! encoder.encode(message)
}

enum SomeEnum<Q : QueueAddable> {
    case playlist(Q)
    func doSome() throws -> Data {
        switch self {
        case .playlist(let queueAddable):
            let encoder = JSONEncoder()

            // No longer error on the following line:
            obj(message: queueAddable)
            return Data()
        }
    }
}

let playlist = Playlist()
let data = try SomeEnum.playlist(playlist).doSome()

Hope it helps!