我是 Swift 和 Xcode 的新手,并且已经开始从 Android 移植一个小应用程序。 它不太大,因此进行嵌套 api 调用(如链)已经有效。
现在我尝试在 XCode 中执行相同的操作,但收到错误:无法构造 URL。
我将放置第一个有效函数的代码:
func apiTest(){
/*Setting up for HTTP requests to https://example.com */
let session = URLSession.shared
let url = URL(string: APIBaseUrl+"get")!
let task = session.dataTask(with: url) { data, response, error in
if error != nil || data == nil {
print("Client error!")
return
}
guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else {
print("Server error!")
return
}
guard let mime = response.mimeType, mime == "application/json" else {
print("Wrong MIME type!")
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: [])
print("OK?")
print(json)
let dict = json as! [String:Any]
print(dict)
print(dict["message"] ?? "Could not read response")
let expected:[String:Any] = ["message": "success"]
print(NSDictionary(dictionary: dict).isEqual(to: expected))
if(NSDictionary(dictionary: dict).isEqual(to: expected)){
//it's working
self.apiTestOk = true
/*Here: continue to a similar function*/
self.apiGetUserPrivateInfo(_id: self.id, _key: self.key)
}
//let message = json as! SimpleMessage //fel i runtime
//print (message.message) //fel i runtime
//let decoder = JSONDecoder()
//let message = try decoder.decode(SimpleMessage.self)
} catch {
print("JSON error: \(error.localizedDescription)")
}
}
task.resume()
/*end http requests*/
}
所以我调用类似的函数
self.apiGetUserPrivateInfo(_id: self.id, _key: self.key)
该函数如下所示:
func apiGetUserPrivateInfo(_id: Int, _key: String){
//"get/userp/{id}/{key}"
let session = URLSession.shared
let u:String = APIBaseUrl+"get/userp/\(_id)/\(_key)"
print (u)
var components = URLComponents()
components.scheme = "https"
components.host = "rapport.se/api"
components.path = u
guard let url = components.url else {
preconditionFailure("Failed to construct URL") // here it fails
}
我想知道是否可能是无法重用的“ session ”。如能得到答复,将不胜感激。
我还使用过:
let url = URL(string: u)!
结果相同。
最佳答案
问题不在于 session (顺便说一句,您通常确实希望“重用” session ,以避免开销),而在于您如何构建 URL,特别是如何使用 URL 组件
。
如果您手动指定 URLComponents
的path
,则它需要以 /
字符开头。但是 URL
有构建带有路径的 URL 的方法:
guard let baseURL = URL(string: "https://rapport.se/api") else { ... }
let url = baseURL.appendingPathComponent(u)
这是比 URLComponents
更简单、更健壮的构建 URL 的方法。顺便说一句,这个 appendingPathComponent
通常是编写 URL 的首选方式,例如,而不是:
let url = URL(string: APIBaseUrl+"get")!
你可能会这样做:
let url = URL(string: APIBaseUrl)!.appendingPathComponent("get")
这让您不再担心“天啊,我的 APIBaseUrl
是否以 /
结尾”,特别是如果 future 程序员存在任何风险的话以删除尾部 /
的方式更改 APIBaseUrl
,突然破坏了您的代码。使用 URL
方法(如 appendingPathComponent
)是实现此目的的一种可靠方法。
如果您想知道何时使用 URLComponents
,那么如果您已有一个包含其路径的 URL,但只需将查询项添加到 URL,那么这是最有用的。例如,空格字符或 &
在包含在 URL 中时需要进行百分比转义,而 URLComponents
可以为我们做到这一点。考虑:
guard var components = URLComponents(string: "https://example.com") else { ... }
components.queryItems = [
URLQueryItem(name: "q", value: "War & Peace")
]
guard let url = components.url else { ... }
这将导致 URL 中的查询组件被百分比转义(即,空格被替换为 %20
,&
被替换为 %26
):
https://example.com?q=War%20%26%20Peace
关于ios - 为什么我无法在嵌套调用尝试中创建 url,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59107095/