Как создать URL с параметрами запроса, содержащими несколько значений для одного и того же ключа в Swift?

Я использую AFNetworking в своем приложении для iOS, и для всех запросов GET, которые он делает, я строю URL-адрес из базового URL-адреса, а затем добавляю параметры, используя пары ключ-значение NSDictionary.

Проблема в том, что мне нужен один и тот же ключ для разных значений.

Вот пример того, что мне нужно, чтобы URL-адрес окончательно выглядел -

http://example.com/.....&id=21212&id=21212&id=33232

В NSDictionary невозможно иметь разные значения в одних и тех же ключах. Поэтому я попробовал NSSet, но не сработало.

let productIDSet: Set = [prodIDArray]
let paramDict = NSMutableDictionary()
paramDict.setObject(productIDSet, forKey: "id")

Ответ 1

Все, что вам нужно, это NSURLComponents. Основная идея - создать кучу элементов запроса для ваших идентификаторов. Здесь код можно вставить в игровое поле:

import UIKit
import XCPlayground

let queryItems = [NSURLQueryItem(name: "id", value: "2121"), NSURLQueryItem(name: "id", value: "3232")]
let urlComps = NSURLComponents(string: "www.apple.com/help")!
urlComps.queryItems = queryItems
let URL = urlComps.URL!
XCPlaygroundPage.currentPage.captureValue(URL.absoluteString, withIdentifier: "URL")

Вы должны увидеть вывод

www.apple.com/help?id=2121&id=3232

Ответ 2

Он может добавить QueryItem к существующему URL.

extension URL {

    func appending(_ queryItem: String, value: String?) -> URL {

        guard var urlComponents = URLComponents(string: absoluteString) else { return absoluteURL }

        // Create array of existing query items
        var queryItems: [URLQueryItem] = urlComponents.queryItems ??  []

        // Create query item
        let queryItem = URLQueryItem(name: queryItem, value: value)

        // Append the new query item in the existing query items array
        queryItems.append(queryItem)

        // Append updated query items array in the url component object
        urlComponents.queryItems = queryItems

        // Returns the url from new url components
        return urlComponents.url!
    }
}

Как использовать

var url = URL(string: "https://www.example.com")!
let finalURL = url.appending("test", value: "123")
                  .appending("test2", value: nil)

Ответ 3

func queryString(_ value: String, params: [String: String]) -> String? {    
    var components = URLComponents(string: value)
    components?.queryItems = params.map { element in URLQueryItem(name: element.key, value: element.value) }

    return components?.url?.absoluteString
}

Ответ 4

Расширение URL для добавления элементов запроса, аналогично идее Бхувана Бхатта, но с другой подписью:

  • он может обнаруживать сбои (возвращая nil вместо self), что позволяет настраивать обработку случаев, когда URL, например, не соответствует RFC 3986.
  • он допускает нулевые значения, фактически передавая любые элементы запроса в качестве параметров.
  • для производительности это позволяет передавать несколько элементов запроса одновременно.
extension URL {
    /// Returns a new URL by adding the query items, or nil if the URL doesn't support it.
    /// URL must conform to RFC 3986.
    func appending(_ queryItems: [URLQueryItem]) -> URL? {
        guard var urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: true) else {
            // URL is not conforming to RFC 3986 (maybe it is only conforming to RFC 1808, RFC 1738, and RFC 2732)
            return nil
        }
        // append the query items to the existing ones
        urlComponents.queryItems = (urlComponents.queryItems ?? []) + queryItems

        // return the url from new url components
        return urlComponents.url
    }
}

использование

let url = URL(string: "https://example.com/...")!
let queryItems = [URLQueryItem(name: "id", value: nil),
                  URLQueryItem(name: "id", value: "22"),
                  URLQueryItem(name: "id", value: "33")]
let newUrl = url.appending(queryItems)!
print(newUrl)

Выход:

https://example.com/...?id&id=22&id=33

Ответ 5

В URL быстрого формирования с несколькими параметрами

func rateConversionURL(with array: [String]) -> URL? {
            var components = URLComponents()
            components.scheme = "https"
            components.host = "example.com"
            components.path = "/hello/"
            components.queryItems = array.map { URLQueryItem(name: "value", value: $0)}

        return components.url
    }

Ответ 6

2019

private func tellServerSomething(_ d: String, _ s: String) {

    var c = URLComponents(string: "https://you.com/info")
    c?.queryItems = [
        URLQueryItem(name: "description", value: d),
        URLQueryItem(name: "summary", value: s)
    ]
    guard let u = c?.url else { return print("url fail") }
    do {
        let r = try String(contentsOf: u)
        print("Server response \(r)")
    }
    catch { return print("comms fail") }
}

Процентное кодирование и все остальное обрабатывается.

Ответ 7

Я думаю, вам просто нужно сделать что-то вроде этого:

let params = ["id" : [1, 2, 3, 4], ...];

который будет закодирован в: .... ID% 5B% 5D = 1 & Идентификатор% 5B% 5D = 2 & Идентификатор% 5B% 5D = 3 & Идентификатор% 5B% 5D = 4....