如果元素符合给定的协议,将数组扩展为符合协议的类型。

9

我想做类似于这样的事情,但是无法正确使用语法或找到任何可以正确编写它的网络资源:

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
    }
}

如果这个数组的元素符合JSONCollectionElement协议,我希望将Array转换为我的协议JSONDecodeable。是否有可能? 如果是这样,语法是什么?


使用泛型,类似于 Array<JSONCollectionElement>。 - Omar Al-Shammary
4个回答

5

目前在Swift中还无法实现这一点。您可以在标准库中看到相同的情况:当使用Equatable元素声明Array时,它不会获得Equatable一致性。


@OrkhanAlikhanov 目前还不可能。我在 XCode 中编译时遇到了一个“带有约束的 'Array' 类型扩展不能有继承子句”的错误。 - doplumi

1
我建议使用包装器。例如:

我建议使用包装器。例如

struct ArrayContainer<T: Decodable>: Container {
    let array: [T]
}

1

Swift 4.2

在 Swift 4.2 中,我可以像这样使用协议扩展数组:

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

        return description
    }
}

确认!谢谢!我快速查找了一些关于Swift 4.2中这个变化的信息,但没有找到。如果有人知道,请分享! - kylejs
而对于可选数组呢?其中元素必须符合某个协议。 - firetrap

1
我不确定这是否是最佳方法,或者苹果是否打算以这种方式使用它。我曾经使用过一次,效果很好:
假设您有以下协议:
protocol MyProtocol {
    var test: Bool { get }
}

你可以对数组执行此操作

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

这是针对字典的内容

extension Dictionary: MyProtocol where Value: MyProtocol {
    var test: Bool {
        return self.values.allSatisfy({ $0.test })
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接