我正在尝试将NULL添加为我的httpBody中的键的值。但是目前仅允许执行[String : String]
。我虽然打算将String
值更改为Any,但这会在整个RestManager中启动多米诺骨牌效果。我想确定,这样做是可能的。或者,如果还有另一种更直观的方法可以这样做。
谢谢。
我的RestManager:
import Foundation
class RestManager {
var httpBody: Data?
var requestHttpHeaders = RestEntity()
var urlQueryParameters = RestEntity()
var httpBodyParameters = RestEntity()
private func addURLQueryParameters(toURL url: URL) -> URL {
if urlQueryParameters.totalItems() > 0 {
guard var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return url }
var queryItems = [URLQueryItem]()
for (key, value) in urlQueryParameters.allValues() {
let item = URLQueryItem(name: key, value: value.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed))
queryItems.append(item)
}
urlComponents.queryItems = queryItems
guard let updatedURL = urlComponents.url else { return url }
return updatedURL
}
return url
}
private func getHttpBody() -> Data? {
guard let contentType = requestHttpHeaders.value(forkey: "Content-Type") else { return nil }
if contentType.contains("application/json") {
return try? JSONSerialization.data(withJSONObject: httpBodyParameters.allValues(), options: [.prettyPrinted, .sortedKeys])
} else {
return httpBody
}
}
private func prepareRequest(withUrl url: URL?, httpBody: Data?, httpMethod: HTTPMethod) -> URLRequest? {
guard let url = url else { return nil }
var request = URLRequest(url: url)
request.httpMethod = httpMethod.rawValue
for (header, value) in requestHttpHeaders.allValues() {
request.setValue(value, forHTTPHeaderField: header)
}
request.httpBody = httpBody
return request
}
func makeRequest(toURL url: URL, withHttpMethod httpMethod: HTTPMethod, completion: @escaping (_ result: Results) -> Void) {
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
let targetURL = self?.addURLQueryParameters(toURL: url)
let httpBody = self?.getHttpBody()
guard let request = self?.prepareRequest(withUrl: targetURL, httpBody: httpBody, httpMethod: httpMethod) else {
completion(Results(withError: CustomError.failedToCreateRequest))
return
}
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
let task = session.dataTask(with: request) {(data, response, error) in
completion(Results(withData: data,
response: Response(fromURLResponse: response),
error: error))
}
task.resume()
}
}
func getData(fromURL url: URL, completion: @escaping (_ data: Data?) -> Void) {
DispatchQueue.global(qos: .userInitiated).async {
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
let task = session.dataTask(with: url, completionHandler: { (data, response, error) in
guard let data = data else { completion(nil); return }
completion(data)
})
task.resume()
}
}
}
extension RestManager {
enum HTTPMethod: String {
case get
case post
case put
case patch
case delete
}
enum CustomError: Error {
case failedToCreateRequest
}
struct RestEntity {
private var values: [String: String] = [ : ]
mutating func add(value: String, forkey key: String) {
values[key] = value
}
func value(forkey key: String) -> String? {
return values[key]
}
func allValues() -> [String : String] {
return values
}
func totalItems() -> Int {
return values.count
}
}
struct Response {
var response: URLResponse?
var httpStatusCode: Int = 0
var headers = RestEntity()
init(fromURLResponse response: URLResponse?) {
guard let response = response else { return }
self.response = response
httpStatusCode = (response as? HTTPURLResponse)?.statusCode ?? 0
if let headerFields = (response as? HTTPURLResponse)?.allHeaderFields {
for (key, value) in headerFields {
headers.add(value: "\(value)", forkey: "\(key)")
}
}
}
}
struct Results {
var data: Data?
var response: Response?
var error: Error?
init(withData data: Data?, response: Response?, error: Error?) {
self.data = data
self.response = response
self.error = error
}
init(withError error: Error?) {
self.error = error
}
}
}
extension RestManager.CustomError: LocalizedError {
public var localizedDescription: String {
switch self {
case .failedToCreateRequest: return NSLocalizedString("Unable to create the URLRequest object.", comment: "")
}
}
}
您首先需要一个字典,该字典的值类型可以保存您的值。类型AnyObject的值不能为nil。因此,类型为[String:AnyObject]的字典的值不能为nil。
如果您有一个字典,其值类型是可选类型,例如[String:AnyObject?],则它可以容纳nil个值。例如,
let x : [String : AnyObject?] = ["foo" : nil]
或
x["foo"] = nil as AnyObject?