需要我的数组符合Swift中的特定类型

时间:2017-09-06 21:13:58

标签: arrays swift

我需要使用以下结构:

import Foundation

protocol QueryValueConvertible {

    func itemsWith(name: String) -> [URLQueryItem]
}

struct QueryList : QueryValueConvertible {

    var elements: [(String, QueryValueConvertible)]

    init(elements: [(String, QueryValueConvertible)]) {
        self.elements = elements
    }

    var isEmpty: Bool {
        return elements.isEmpty
    }

    var percentEncodedQuery: String {
        let allowedCharacters = QueryList.percentEncodedQueryAllowedCharacters
        return items.map { (item) -> String in
            guard let encodedName = item.name.addingPercentEncoding(withAllowedCharacters: allowedCharacters) else {
                return ""
            }
            if let value = item.value, let encodedValue = value.addingPercentEncoding(withAllowedCharacters: allowedCharacters) {
                return encodedName + "=" + encodedValue
            } else {
                return encodedName
            }
        }.joined(separator: "&")
    }

    var items: [URLQueryItem] {
        return elements.flatMap { (name, value) -> [URLQueryItem] in
            return value.itemsWith(name: name)
        }
    }

    func itemsWith(name: String) -> [URLQueryItem] {
        let prefix = name
        guard !elements.isEmpty else {
            return [URLQueryItem(name: "\(name)[]", value: nil)]
        }
        return elements.flatMap { (suffix, value) -> [URLQueryItem] in
            let name = "\(prefix)[\(suffix)]"
            return value.itemsWith(name: name)
        }
    }

    private static let percentEncodedQueryAllowedCharacters: CharacterSet = { () -> CharacterSet in
        // We are far more conservative than NSURLComponents because nobody implements RFC 3986.
        // HTML5 allows the following restricted set of characters to appear in query.
        // cf: http://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
        let characters = NSMutableCharacterSet()
        characters.addCharacters(in: NSRange(location: 0x2a, length: 1))  // *
        characters.addCharacters(in: NSRange(location: 0x2d, length: 1))  // -
        characters.addCharacters(in: NSRange(location: 0x2e, length: 1))  // .
        characters.addCharacters(in: NSRange(location: 0x30, length: 10)) // 0-9
        characters.addCharacters(in: NSRange(location: 0x41, length: 26)) // A-Z
        characters.addCharacters(in: NSRange(location: 0x5f, length: 1))  // _
        characters.addCharacters(in: NSRange(location: 0x61, length: 26)) // a-z
        return characters as CharacterSet
    }()
}

extension QueryList : ExpressibleByDictionaryLiteral {

    init(dictionaryLiteral elements: (String, QueryValueConvertible)...) {
        self.elements = elements
    }

    init<S : Sequence>(_ elements: S)
        where S.Iterator.Element == (String, QueryValueConvertible)
    {
        self.elements = Array(elements)
    }
}

extension QueryList : ExpressibleByArrayLiteral {

    init(arrayLiteral elements: QueryValueConvertible...) {
        self.elements = elements.enumerated().map { (index, value) in (String(index), value) }
    }

    init<S : Sequence>(_ elements: S)
        where S.Iterator.Element : QueryValueConvertible
    {
        self.elements = elements.enumerated().map { (index, value) in (String(index), value) }
    }
}

func + (lhs: QueryList, rhs: QueryList) -> QueryList {
    return QueryList(elements: lhs.elements + rhs.elements)
}

func += (lhs: inout QueryList, rhs: QueryList) {
    lhs = QueryList(elements: lhs.elements + rhs.elements)
}

extension String : QueryValueConvertible {

    func itemsWith(name: String) -> [URLQueryItem] {
        return [URLQueryItem(name: name, value: self)]
    }
}

extension Int : QueryValueConvertible {

    func itemsWith(name: String) -> [URLQueryItem] {
        return [URLQueryItem(name: name, value: String(self))]
    }
}

extension Bool : QueryValueConvertible {

    func itemsWith(name: String) -> [URLQueryItem] {
        return [URLQueryItem(name: name, value: self ? "true" : "false")]
    }
}

在另一个类中,我有以下代码:

var sampleData = [
    "foo": someString,
    "bar": anotherString    
] as QueryList

let myDict: [String: Bool] = ["example": true]
var myArray = [[String:Any]]()
myArray.append(myDict)
sampleData += ["myData": myArray]// this is where the error is occurring.

我收到以下编译时错误:

"Value of type [[String: Any]] does not conform to expected dictionary value type "QueryValueConvertible"

我要做的是将包含键/值对“String”的字典提交到包含在Array中的“Bool”。反过来,该数组也被引用为“String”类型的键。

2 个答案:

答案 0 :(得分:0)

在声明时,只需将myArray的类型从[[String:Any]]更改为[[String:QueryValueConvertible]]。 或者你可以将它初始化为相同的效果:

var myArray: [[String: QueryValueConvertible]] = [myDict]

答案 1 :(得分:-1)

Xcode对你的代码做的第一件事是建议你转:

sampleData += ["myData": myArray]

sampleData += ["myData": myArray as! QueryValueConvertible]

变量myArray不是正确的类型。您可以将其投射或初始化为QueryValueConvertible。如果你投了它,我建议使用as?而不是as!,然后在添加之前检查Optional