Swift 如何在Alamofire.request()之外使用JSON?

Swift 如何在Alamofire.request()之外使用JSON?,swift,alamofire,Swift,Alamofire,我试图从Alamofire返回JSON字典。问题在于,当将JSON赋值给外部变量时,赋值会保存在Alamofire.request块内并只读,其值之外不会保存(对我来说很神奇)。我做错了什么 我第一次这样做。我尝试使用URLSession.shared.dataTask,但我也无法从任务返回值。 我注意到,首先在返回res行触发断点,然后在返回json行触发断点,然后在打印(json)行触发断点。我不知道为什么 struct resultMsg { var message: [Strin

我试图从
Alamofire
返回
JSON
字典。问题在于,当将
JSON
赋值给外部变量时,赋值会保存在
Alamofire.request
块内并只读,其值之外不会保存(对我来说很神奇)。我做错了什么

我第一次这样做。我尝试使用
URLSession.shared.dataTask
,但我也无法从任务返回值。 我注意到,首先在
返回res
行触发断点,然后在
返回json
行触发断点,然后在
打印(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
}

这是因为网络请求通常是异步的。当您调用
Alamofire.request(…)
时,网络请求启动,
request
立即返回。与此同时,社交活动也发生在后台。由于
request
已返回,因此您的
sendGET
功能将立即继续下一行

稍后,当网络请求完成时,将调用完成块。您将该值分配给
res
,但为时已晚,因为
sendGET
在请求启动时已返回空字典

通常这很快,但是想象一下这将需要很长的时间。毕竟,有时候它将花费很长时间。如果网络连接超时,可能需要几分钟

有不同的处理方法

  • 在一种方法中,您可以将
    res
    作为该代码所在类的属性。然后,您的完成块仍然会为
    res
    分配一个值,然后调用一些新代码来告诉您的类结果可用
  • 在另一种方法中,您可以修改完成闭包,将JSON数据传递给直接使用数据的其他函数。添加一些新函数,其参数类型为
    [String:Any]
    ,并从完成闭包调用此函数

哪一个更好取决于你的应用程序中还发生了什么,以及你在获得数据时需要如何使用这些数据。

汤姆·哈林顿是对的。更好的方法是将完成块添加到

func sendGET

当您得到json时,调用completion,就是这样


快乐编码

总的来说,我觉得现在编写
Swift
程序还为时过早。我想为用
C#
编写的iOS移植我的项目,我认为本机应用程序会更好,而且这些闭包有很多陷阱。但是在
C#
中,一切都很简单:只需在函数之前编写
wait
,但在那里并不总是需要它

感谢所有帮助过我的人

UPD 1

我知道这可能是愚蠢的,但只有这种方法在闭包方面没有不必要的麻烦。但是重复的代码会变得很多

UPD 2

同样不幸的是,我不得不使用
GET
而不是
POST
,因为在
POST
中,服务器没有收到任何数据。我用echo json\u encode($\u POST)检查了它。但我也可能没有使用阿拉莫菲尔

UPD 3

最后,在汤姆·哈林顿的建议下,我找到了一个更好的解决方案。在我找到解决方案之前,它在
DispatchQueue.main.async
中不起作用,就像
Alamofire.request
(我建议
Alamofire
使用
main.async
)。因此,我做到了

UPD 4

我又错了。UPD 3中的溶液有时在环体中冻结。我最终决定学习使用自己的补全,我做到了:)


我会给你一个方法。在Swift 4.2的帮助下,已经启动了,因此您可以轻松地解析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(投诉:@escaping(Result)->Void){
让URL字符串=”http://examples"
请求(urlString,方法:.get,编码:URLEncoding.default,头:…)
.responseData{(响应)in
开关响应。结果{
案例.成功(让数据):
做{
let faults=try Decoders.plainDateDecoder.decode([faults].self,from:data)
抱怨(.success(faults))
}抓住{
投诉(.failure(Error.serializationError(internal:Error)))
}
案例。失败(let错误):
投诉(.failure(Error.networkError(internal:Error)))
}
}
}  

对于您的版本,编译器要求添加
@escaping
func sendGET(方法:String,数据:[String:String],完成:@escaping([String:Any])->Void)
然后我添加
sendGET
完成(res)和Authorize()
sendGET(方法:“auth.php”,数据:data){dict in
json.message=dict
}
但断点按相同顺序触发
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
    })
}
public struct Faults: Decodable {

    public enum CodingKeys:String,CodingKey{
        case guid
        case adi
    }

    public let guid:Int
    public let adi:String
}
 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)))
            }
        }
    }