我尝试从JSON
返回Alamofire
字典。问题在于,当将JSON
分配给外部变量时,分配的值将被保存并只能在Alamofire.request
块内部读取,而在其值外部则不被保存(对我来说很神奇)。我做错了什么?
我第一次这样做。我尝试使用URLSession.shared.dataTask
,但也无法从任务返回值。
我注意到,断点首先在return res
行上触发,然后在return json
行上触发,然后在print (JSON)
行上触发。我不知道为什么。
struct resultMsg {
var message: [String:Any] = [:]
init() { }
init(message: [String:Any]) {
self.message = message
}
}
func sendGET(method: String, data: [String:String]) -> [String:Any] {
let resultURL: String = rootURI + method
let url = URL(string: resultURL)!
var res: [String:Any] = [:]
Alamofire.request(url, method: .post, parameters: data, encoding: JSONEncoding.default)
.responseJSON { response in
print(response)
if let status = response.response?.statusCode {
switch(status){
case 201:
print("example success")
default:
print("error with response status: \(status)")
}
}
//to get JSON return value
if let result = response.result.value {
let JSON = result as! NSDictionary
res = JSON as! [String : Any]
print(JSON) // Here res is contain actualy json
}
}
return res // Here res equal [:]
}
public func Authorize() -> resultMsg {
let data: [String:String] = ["login":login,
"pass":pass]
var json = resultMsg.init()
json.message = sendGET(method: "auth.php", data: data)
return json
}
答案 0 :(得分:1)
这是因为网络请求通常是异步的。当您呼叫Alamofire.request(...)
时,网络请求开始,并且request
立即返回。同时,网络事务在后台发生。由于request
已返回,因此您的sendGET
函数将立即继续到下一行。
稍后,当网络请求完成时,将调用完成块。您将值分配给res
,但为时已晚,因为sendGET
在请求开始时已经返回了一个空字典。
通常这很快,但是可以帮助我们想象这将花费很长时间。毕竟,有时候 会花费很长时间。如果网络连接超时,则可能需要几分钟。
有不同的处理方式。
res
设置为该代码所在类的属性。然后,您的完成块仍将为res
分配一个值,然后调用一些新代码来告诉您的班级结果可用。[String : Any]
的新函数,然后从完成闭包中调用该函数。哪个更好,取决于您应用程序中发生的其他事情以及获取数据时如何使用这些数据。
答案 1 :(得分:0)
汤姆·哈灵顿是对的。更好的方法是在
中添加一个完成块func sendGET
喜欢
func sendGET(method: String, data: [String:String], completion: ([String:Any]) -> Void)
并在获取json时调用完成函数,就这样。
快乐编码
答案 2 :(得分:0)
总的来说,我认为编写Swift
程序为时尚早。我想移植用C#
编写的iOS项目,我认为本机应用程序会更好,并且这些关闭有很多陷阱。但是在C#
中,一切都变得更加简单:只需在函数前编写await
,但并非总是如此。
感谢所有帮助过我们的人...
UPD 1
我知道这可能是愚蠢的,但是只有这种方法才能正常工作而不会给闭包带来不必要的麻烦。但是重复的代码会变得很多。
UPD 2
很不幸,我还不得不使用GET
而不是POST
,因为在POST
中服务器没有收到任何数据。我用echo json_encode($_POST);
进行了检查。但我可能还没有使用过Alamofire
。
UPD 3
最后,汤姆·哈灵顿的建议使我获得了更好的解决方案。在找到解决方案like so之前,但它在DispatchQueue.main.async
中却无法像Alamofire.request
一样工作(我建议Alamofire
使用main.async
)。因此,我做了like here。
UPD 4
我又错了。 UPD 3中的溶液有时会在回路体内冻结。我决定最终学习使用自己的完成功能,我做到了:)
func sendGET(_ method: String,_ data: [String:String],_ instance: CommonClass, completion : @escaping (Any?)->()) {
let url = getURL(method: method, data: data)
Alamofire.request(url, method: .get).responseJSON { response in
if let status = response.response?.statusCode {
instance.manageStatus(status)
}
if let result = response.result.value {
completion(result)
}
}
}
func someFunc(_ instance: CommonClass) {
let data: [String:String] = ["id":String(id),
"route":route]
sendGET("getTaskData.php", data, instance, completion: { response in
let JSON = response as! [[String:String]]
// Do something with JSON
})
}
答案 3 :(得分:0)
我会为您提供一种方法。借助Swift 4.2,Codable已启动,因此您可以轻松地进行JSON解析并摆脱代码。
示例类
public struct Faults: Decodable {
public enum CodingKeys:String,CodingKey{
case guid
case adi
}
public let guid:Int
public let adi:String
}
和json解析(获取Web服务)
public func fetchFaults(complation: @escaping (Result<[Faults]>) -> Void) {
let urlString = "http://examples"
request(urlString, method: .get, encoding: URLEncoding.default, headers: ...)
.responseData { (response) in
switch response.result {
case .success(let data):
do {
let faults = try Decoders.plainDateDecoder.decode([Faults].self, from: data)
complation(.success(faults))
} catch{
complation(.failure(Error.serializationError(internal: error)))
}
case .failure(let error):
complation(.failure(Error.networkError(internal: error)))
}
}
}