How do I convert url.query to a dictionary in Swift?

前端 未结 6 1378
不知归路
不知归路 2021-02-09 02:06

I have a URL coming in to the AppDelegate method:

func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) ->         


        
6条回答
  •  野性不改
    2021-02-09 02:37

    Details

    • Swift 5
    • Xcode Version 10.2.1 (10E1001)

    Solution

    import Foundation
    
    // MARK: - [URLQueryItem] to [String: Any]
    
    extension Array where Element == URLQueryItem {
        func toDictionary() -> [String: Any] {
            var dictionary = [String: Any]()
            for queryItem in self {
                guard let value = queryItem.value?.toCorrectType() else { continue }
                if queryItem.name.contains("[]") {
                    let key = queryItem.name.replacingOccurrences(of: "[]", with: "")
                    let array = dictionary[key] as? [Any] ?? []
                    dictionary[key] = array + [value]
                } else {
                    dictionary[queryItem.name] = value
                }
            }
            return dictionary
        }
    }
    
    extension String {
    
        // MARK: - String to [URLQueryItem]
    
        func toURLQueryItems() -> [URLQueryItem]? {
            guard let urlString = self.removingPercentEncoding, let url = URL(string: urlString) else { return nil }
            if let querItems = url.toQueryItems() { return querItems }
            var urlComponents = URLComponents()
            urlComponents.query = urlString
            return urlComponents.queryItems
        }
    
        // MARK: - attempt to cast string to correct type (int, bool...)
    
        func toCorrectType() -> Any {
            let types: [LosslessStringConvertible.Type] = [Bool.self, Int.self, Double.self]
            func cast(to: T) -> Any? { return (to.self as? LosslessStringConvertible.Type)?.init(self) }
            for type in types { if let value = cast(to: type) { return value } }
            return self
        }
    }
    
    // MARK: - URL to [URLQueryItem]
    
    extension URL {
        func toQueryItems() -> [URLQueryItem]? { return URLComponents(url: self, resolvingAgainstBaseURL: false)?.queryItems }
    }
    
    // MARK: - create [URLQueryItem] from [AnyHashable: Any] or [any]
    
    extension URLQueryItem {
        private static var _bracketsString: String { return "[]" }
        static func create(from values: [Any], with key: String) -> [URLQueryItem] {
            let _key = key.contains(_bracketsString) ? key : key + _bracketsString
            return values.compactMap { value -> URLQueryItem? in
                if value is [Any] || value is [AnyHashable: Any] { return nil }
                return URLQueryItem(name: _key, value: value as? String ?? "\(value)")
            }
        }
    
        static func create(from values: [AnyHashable: Any]) -> [URLQueryItem] {
            return values.flatMap { element -> [URLQueryItem] in
                if element.value is [AnyHashable: Any] { return [] }
                let key = element.key as? String ?? "String"
                if let values = element.value as? [Any] { return URLQueryItem.create(from: values, with: key) }
                return [URLQueryItem(name: key, value: element.value as? String ?? "\(element.value)")]
            }
        }
    }
    
     // MARK: - [AnyHashable: Any] to [URLQueryItem]
    
    extension Dictionary where Value: Any {
        func toURLQueryItems() -> [URLQueryItem] { return URLQueryItem.create(from: self) }
    }
    

    Usage

    url.toQueryItems()
    url.toQueryItems()?.toDictionary()
    
    urlString.toURLQueryItems()
    urlString.toURLQueryItems()?.toDictionary()
    
    urlQueryString?.toURLQueryItems()
    urlQueryString?.toURLQueryItems()?.toDictionary()
    
    let dictionary = ["aaa": [1234], "bbb": ["a", "b", "c"]]
    dictionary.toURLQueryItems()
    

    Full sample

    var urlString = "https://example.com/l57?condition%5B%5D=31&brand%5B%5D=289&brand%5B%5D=291&brand%5B%5D=32&year%5B%5D=23259&year%5B%5D=23757&ships_from_region%5B%5D=23684&ships_from_region%5B%5D=23683"
    let url = URL(string: urlString)!
    var urlQueryString = url.query
    
    print("URL:\n\(urlString)")
    print("URL query string:\n\(String(describing: urlQueryString))\n")
    
    print("get [URLQueryItem] from URL:\n\(String(describing: url.toQueryItems()))\n")
    print("get [String: Any] from URL:\n\(String(describing: url.toQueryItems()?.toDictionary()))\n")
    
    print("get [URLQueryItem] from url string (absoluteString):\n\(String(describing: urlString.toURLQueryItems()))\n")
    print("get [String:Any] from url string (absoluteString):\n\(String(describing: urlString.toURLQueryItems()?.toDictionary()))\n")
    
    print("get [URLQueryItem] from url string (only query):\n\(String(describing: urlQueryString?.toURLQueryItems()))\n")
    print("get [String:Any] from url string (only query):\n\(String(describing: urlQueryString?.toURLQueryItems()?.toDictionary()))\n")
    
    var dict =  [String: Any]()
    dict = ["aaa": [1234], "bbb": [1234: 22], "ccc": ["a", "b", "c"], "ffffd": [[1,2,3], [4,5,6]], "eee[]": [1,2,4], "fff": "value", "ggg": 123]
    print("Dict: \(dict)")
    print("Dict to [URLQueryItem]: \(dict.toURLQueryItems())")
    print("Dict to query oriented dictionary: \(dict.toURLQueryItems().toDictionary())")
    

    Full sample output

    URL:
    https://example.com/l57?condition%5B%5D=31&brand%5B%5D=289&brand%5B%5D=291&brand%5B%5D=32&year%5B%5D=23259&year%5B%5D=23757&ships_from_region%5B%5D=23684&ships_from_region%5B%5D=23683
    URL query string:
    Optional("condition%5B%5D=31&brand%5B%5D=289&brand%5B%5D=291&brand%5B%5D=32&year%5B%5D=23259&year%5B%5D=23757&ships_from_region%5B%5D=23684&ships_from_region%5B%5D=23683")
    
    get [URLQueryItem] from URL:
    Optional([condition[]=31, brand[]=289, brand[]=291, brand[]=32, year[]=23259, year[]=23757, ships_from_region[]=23684, ships_from_region[]=23683])
    
    get [String: Any] from URL:
    Optional(["condition": [31], "ships_from_region": [23684, 23683], "year": [23259, 23757], "brand": [289, 291, 32]])
    
    get [URLQueryItem] from url string (absoluteString):
    Optional([condition[]=31, brand[]=289, brand[]=291, brand[]=32, year[]=23259, year[]=23757, ships_from_region[]=23684, ships_from_region[]=23683])
    
    get [String:Any] from url string (absoluteString):
    Optional(["year": [23259, 23757], "ships_from_region": [23684, 23683], "condition": [31], "brand": [289, 291, 32]])
    
    get [URLQueryItem] from url string (only query):
    Optional([condition[]=31, brand[]=289, brand[]=291, brand[]=32, year[]=23259, year[]=23757, ships_from_region[]=23684, ships_from_region[]=23683])
    
    get [String:Any] from url string (only query):
    Optional(["condition": [31], "brand": [289, 291, 32], "ships_from_region": [23684, 23683], "year": [23259, 23757]])
    
    Dict: ["ccc": ["a", "b", "c"], "eee[]": [1, 2, 4], "bbb": [1234: 22], "fff": "value", "ffffd": [[1, 2, 3], [4, 5, 6]], "aaa": [1234], "ggg": 123]
    Dict to [URLQueryItem]: [ccc[]=a, ccc[]=b, ccc[]=c, ggg=123, fff=value, aaa[]=1234, eee[]=1, eee[]=2, eee[]=4]
    Dict to query oriented dictionary: ["ccc": ["a", "b", "c"], "aaa": [1234], "fff": "value", "eee": [1, 2, 4], "ggg": 123]
    

提交回复
热议问题