Extend Array to conform to protocol if Element conforms to given protocol
Asked Answered
B

4

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?

Blalock answered 19/10, 2015 at 16:22 Comment(1)
Use generics something like Array<JSONCollectionElement>Antione
C
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
    }
}
Courteous answered 21/10, 2018 at 18:15 Comment(2)
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!Blalock
And for optional array? Where Element must conform some protocolEverest
S
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.

Saharanpur answered 19/10, 2015 at 18:19 Comment(1)
@OrkhanAlikhanov still not possible. I am getting a Extension of type 'Array' with constraints cannot have an inheritance clause build time error from XCode.Libido
G
1

I would suggest using a wrapper. For instance

struct ArrayContainer<T: Decodable>: Container {
    let array: [T]
}
Gesticulative answered 19/1, 2018 at 10:6 Comment(0)
C
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
    }
}
Courteous answered 21/10, 2018 at 18:15 Comment(2)
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!Blalock
And for optional array? Where Element must conform some protocolEverest
S
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 })
    }
}
Scanderbeg answered 1/12, 2018 at 17:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.