Array of Protocols and Subscript

Hi

I have an array of protocols and would like to retrieve items from the array based on an enum. Something like this:

enum ServiceType: String {
   case car
   case boat
}

protocol ServiceDescriptor {
   var contact: String { get }
   var type: ServiceType { get }
}

struct CarService: ServiceDescriptor {
   let contact: String
   let type: ServiceType
}

struct BoatService: ServiceDescriptor {
   let contact: String
   let type: ServiceType
}

class Repair {
    init(allowedRepairs: [ServiceDescriptor]) {
        self.allowedRepairs = allowedRepairs
    }

    let allowedRepairs: [ServiceDescriptor]

    subscript(type: ServiceType) -> ServiceDescriptor? {
       get {
           return allowedRepairs.first(where: { $0.type == type })
       }
    }
}


let carService = CarService(contact: "Fred", type: .car)
let boatService = BoatService(contact: "Jane", type: .boat)

let repair = Repair(allowedRepairs: [carService, boatService])

print(repair.allowedRepairs[type: ServiceType.boat]). // error

I end up with errors in Playgrounds as:

no exact matches in call to subscript 

found candidate with type '(ServiceType) -> Array.SubSequence' (aka '(ServiceType) -> ArraySlice< ServiceDescriptor >')

The following works:

print(repair.allowedRepairs[0])

I'm obviously coming about this the wrong way, I wanted to avoid a dictionary i.e let allowedRepairs: [ServiceType: ServiceDescriptor] because that would lend itself to assigning the wrong ServiceDescriptor to a ServiceType and it kinda duplicates the data.

Is there a another way to have a custom argument in subscript instead of int?

Many thanks

Replies

In an array, the index must be Int.

So as you guessed, you should use dictionary.

You could do something like this (not tested):

enum ServiceType: String {
   case car
   case boat
}

protocol ServiceDescriptor {
   var contact: String { get }
   var type: ServiceType { get }
}

struct CarService: ServiceDescriptor {
   let contact: String
   let type: ServiceType
}

struct BoatService: ServiceDescriptor {
   let contact: String
   let type: ServiceType
}


typealias ServiceDict = [ServiceType: ServiceDescriptor]
class Repair {
    init(allowedRepairs: ServiceDict) {
        self.allowedRepairs = allowedRepairs
    }

    let allowedRepairs: ServiceDict

}


let carService = CarService(contact: "Fred", type: .car)
let boatService = BoatService(contact: "Jane", type: .boat)

let repair = Repair(allowedRepairs: [.car: carService, .boat:boatService])

print(repair.allowedRepairs[ServiceType.boat]) // No error

Hi Claude31

I thought this might have to be the solution and of course it works. I did try making enum ServiceType: Int and doing repairs.allowRepairs[ServiceType.boat] which also worked so long as the dictionary value matched the index of the enum.

So another issue will be JSON codable of Dictionary[ServiceType: ServiceDescriptor], all sorts of error here.

Wouldn't happen to have some ideas around codable of a Dictionary[Enum: Protocols]?

If you use Int, then of course you can use it to index an array (just take care to start from 0).

To make a protocol Codable, just declare it as Codable ; idem for enum.

If you get an error and need to define encode and decode, get details here with an example:

https://developer.apple.com/forums/thread/79327