9

I'd like to do something like this, but can't get the syntax right or find anywhere on the web that gives the right way to write it:

protocol JSONDecodeable {
    static func withJSON(json: NSDictionary) -> Self?
}

protocol JSONCollectionElement: JSONDecodeable {
    static var key: String { get }
}

extension Array: JSONDecodeable where Element: JSONCollectionElement {
    static func withJSON(json: NSDictionary) -> Array? {
        var array: [Element]?
        if let elementJSON = json[Element.key] as? [NSDictionary] {
            array = [Element]()
            for dict in elementJSON {
                if let element = Element.withJSON(dict) {
                    array?.append(element)
                }
            }
        }
        return array
    }
}

So I want to conform Array to my protocol JSONDecodeable only when the elements of this array conform to JSONCollectionElement.

Is this possible? If so, what's the syntax?

kylejs
  • 1,128
  • 11
  • 25

4 Answers4

5

This isn't possible yet in Swift. You can see the same thing happen in the standard library: Array doesn't gain Equatable conformance when it's declared with Equatable elements.

Nate Cook
  • 92,417
  • 32
  • 217
  • 178
  • @OrkhanAlikhanov still not possible. I am getting a `Extension of type 'Array' with constraints cannot have an inheritance clause` build time error from XCode. – doplumi Nov 30 '17 at 08:20
1

I would suggest using a wrapper. For instance

struct ArrayContainer<T: Decodable>: Container {
    let array: [T]
}
Vyacheslav
  • 26,359
  • 19
  • 112
  • 194
1

Swift 4.2

In Swift 4.2 I was able to extend an array with the elements conforming to a protocol like this:

public extension Array where Element: CustomStringConvertible{
    public var customDescription: String{
        var description = ""
        for element in self{
            description += element.description + "\n"
        }

        return description
    }
}
the Reverend
  • 12,305
  • 10
  • 66
  • 121
  • Confirmed! Thank you! I had a quick look around for some info on this change in Swift 4.2, but couldn't find any. If anyone's got it please share! – kylejs Nov 25 '18 at 21:57
  • And for optional array? Where Element must conform some protocol – firetrap May 10 '20 at 17:07
1

I don't know if this is the best approach or if apple intended it to be used this way. I used this once and it worked well for me:

Say you have the following protocol

protocol MyProtocol {
    var test: Bool { get }
}

You can do this for Arrays

extension Array: MyProtocol where Element: MyProtocol {
    var test: Bool {
        return self.allSatisfy({ $0.test })
    }
}

And this for Dictionaries

extension Dictionary: MyProtocol where Value: MyProtocol {
    var test: Bool {
        return self.values.allSatisfy({ $0.test })
    }
}
Jacob
  • 1,052
  • 8
  • 10