难以在Swift中施法

时间:2017-09-06 20:29:25

标签: arrays swift dictionary

我需要使用以下结构:

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 as! QueryValueConvertible]// this is where the error is occurring.

当我运行我的代码时,我收到以下错误:

Could not cast value of type 'Swift.Array<Swift.Dictionary<Swift.String, Any>>' (0x608000a9bb40) to 'QueryValueConvertible' (0x6080004709d8).

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

施法是一种启示,而不是改变;你不能施展到已经不存在的东西。因此,除非myArray as! QueryValueConvertible已经 一个QueryValueConvertible,否则您无法说myArray

嗯,它不是。您只有三种符合QueryValueConvertible的类型:String,Int和Bool。 myArray不是那些 - 它是一个阵列!所以强迫施法自然会失败,你就会崩溃。