如何在 Swift 中解析来自 Alamofire API 的 JSON 响应?
Posted
技术标签:
【中文标题】如何在 Swift 中解析来自 Alamofire API 的 JSON 响应?【英文标题】:How to parse JSON response from Alamofire API in Swift? 【发布时间】:2014-09-30 07:12:13 【问题描述】:按照我编写的代码,我也收到了 JSON 格式的响应,但 JSON 的类型是“AnyObject”,我无法将其转换为数组以便我可以使用它。
Alamofire.request(.POST, "MY URL", parameters:parameters, encoding: .JSON) .responseJSON
(request, response, JSON, error) in
println(JSON?)
【问题讨论】:
我没有否决您的问题,但我认为这是因为解析 JSON 的主题过于广泛,无法给出明确、直接的答案。试试这个名为 SwiftyJSON 的库。 @Isuru 没关系!我看过那个图书馆,但我正在使用 Alamofire!但是你能把你使用过 SwiftyJson 的示例代码发给我吗?那里的代码对我不起作用! 我也使用 SwiftyJSON 和 Alamofire。我只是像这样let data = JSONValue(JSON!)
传递响应。然后我可以提取像data["Id"]
这样的值。 SwiftyJSON 文档提供了如何以所需类型检索这些值的示例。你到底得到了什么错误?
【参考方案1】:
Swift 2.0 Alamofire 3.0 的答案实际上应该更像这样:
Alamofire.request(.POST, url, parameters: parameters, encoding:.JSON).responseJSON
response in switch response.result
case .Success(let JSON):
print("Success with JSON: \(JSON)")
let response = JSON as! NSDictionary
//example if there is an id
let userId = response.objectForKey("id")!
case .Failure(let error):
print("Request failed with error: \(error)")
https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%203.0%20Migration%20Guide.md
Alamofire 4.0 和 Swift 3.0 更新:
Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default)
.responseJSON response in
print(response)
//to get status code
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
print(JSON)
【讨论】:
如何获得 JSON 的实际内容?这是什么类型的物体?设计和文档非常模糊,我无法弄清楚,也无法在互联网上找到任何示例...... 我在答案中添加了几行应该有帮助的内容。 @JosephGeraghty 具有编码参数会导致编译器告诉我有一个额外的参数调用...知道吗? @jch-duran 不积极,但我隐约记得不久前遇到过类似的事情。我认为这与库未更新或可能与 swift 版本不同步有关。确保您使用的是最新版本可能会有所帮助 @AlexWorden 同意,这个页面帮助我回答了这些问题并提供了一个很好的解决方案:github.com/SwiftyJSON/SwiftyJSON【参考方案2】:如上所述,您可以使用 SwiftyJSON 库并像我在下面所做的那样获取您的值
Alamofire.request(.POST, "MY URL", parameters:parameters, encoding: .JSON) .responseJSON
(request, response, data, error) in
var json = JSON(data: data!)
println(json)
println(json["productList"][1])
我的 json 产品列表从脚本返回
"productList" :[
"productName" : "PIZZA","id" : "1","productRate" : "120.00","productDescription" : "PIZZA AT 120Rs","productImage" : "uploads\/pizza.jpeg",
"productName" : "BURGER","id" : "2","productRate" : "100.00","productDescription" : "BURGER AT Rs 100","productImage" : "uploads/Burgers.jpg"
]
输出:
"productName" : "BURGER",
"id" : "2",
"productRate" : "100.00",
"productDescription" : "BURGER AT Rs 100",
"productImage" : "uploads/Burgers.jpg"
【讨论】:
我在安装后尝试使用 SwiftyJson 的东西,但在 SwiftyJson 文件中出现了大约 300 个错误,有人遇到过这个问题吗? i',使用 Xcode 6.2 版、ios 8.1 版、cocoaPods 36,如 [github] (github.com/SwiftyJSON/SwiftyJSON) 文档中所述。 老兄。有哪些错误?问一个单独的问题并提供一些细节。 SwiftyJSON 就像魔法一样美丽。尽可能使用它。 确实应该将 json 字符串转换为具体的 swift 对象,以便您可以以自然的方式干净地使用它。通过字符串名称访问字段是荒谬的并且容易出错。【参考方案3】:Swift 3、Alamofire 4.4 和 SwiftyJSON:
Alamofire.request(url, method: .get)
.responseJSON response in
if response.data != nil
let json = JSON(data: response.data!)
let name = json["people"][0]["name"].string
if name != nil
print(name!)
这将解析这个 JSON 输入:
people: [
name: 'John' ,
name: 'Dave'
]
【讨论】:
还有一个 Alamofire Swifty-JSON 专用插件,无需显式的JSON()
转换:github.com/SwiftyJSON/Alamofire-SwiftyJSON
这对我有帮助,但 JSON 方法确实有一些问题,因为抛出异常【参考方案4】:
我在 GitHub 上找到了 Swift2
的答案https://github.com/Alamofire/Alamofire/issues/641
Alamofire.request(.GET, URLString, parameters: ["foo": "bar"])
.responseJSON request, response, result in
switch result
case .Success(let JSON):
print("Success with JSON: \(JSON)")
case .Failure(let data, let error):
print("Request failed with error: \(error)")
if let data = data
print("Response data: \(NSString(data: data, encoding: NSUTF8StringEncoding)!)")
【讨论】:
这是 Swift 2.0 + Alamofire JSON 解析的正确版本。 嗯,我仍然无法构建错误消息:'(_, _, _) -> Void' 不能转换为 'Response -> Void' @alex 请参阅this answer 了解我用来解决它的方法。 非常感谢!你不知道我尝试了多少东西来正确显示来自服务器的响应消息,救命恩人!【参考方案5】:我既不是 JSON 专家也不是 Swift 专家,但以下内容对我有用。 :) 我已经从我当前的应用程序中提取了代码,并且只将“MyLog 更改为 println”,并用空格缩进以使其显示为代码块(希望我没有破坏它)。
func getServerCourseVersion()
Alamofire.request(.GET,"\(PUBLIC_URL)/vtcver.php")
.responseJSON (_,_, JSON, _) in
if let jsonResult = JSON as? Array<Dictionary<String,String>>
let courseName = jsonResult[0]["courseName"]
let courseVersion = jsonResult[0]["courseVersion"]
let courseZipFile = jsonResult[0]["courseZipFile"]
println("JSON: courseName: \(courseName)")
println("JSON: courseVersion: \(courseVersion)")
println("JSON: courseZipFile: \(courseZipFile)")
希望这会有所帮助。
编辑:
作为参考,这是我的 PHP 脚本返回的内容:
["courseName": "Training Title","courseVersion": "1.01","courseZipFile": "101/files.zip"]
【讨论】:
这应该是选择的答案,尽管您可能想要更新它,因为 Alamofire 已经稍微更新了他们的方法【参考方案6】:斯威夫特 5
class User: Decodable
var name: String
var email: String
var token: String
enum CodingKeys: String, CodingKey
case name
case email
case token
public required init(from decoder: Decoder) throws
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
self.email = try container.decode(String.self, forKey: .email)
self.token = try container.decode(String.self, forKey: .token)
Alamofire API
Alamofire.request("url.endpoint/path", method: .get, parameters: params, encoding: URLEncoding.queryString, headers: nil)
.validate()
.responseJSON response in
switch (response.result)
case .success( _):
do
let users = try JSONDecoder().decode([User].self, from: response.data!)
print(users)
catch let error as NSError
print("Failed to load: \(error.localizedDescription)")
case .failure(let error):
print("Request error: \(error.localizedDescription)")
【讨论】:
如果您有Decodable
类型,您应该使用responseDecodable
,而不是responseJSON
。【参考方案7】:
斯威夫特 3
pod 'Alamofire', '~> 4.4'
pod 'SwiftyJSON'
File json format:
"codeAd":
"dateExpire": "2017/12/11",
"codeRemoveAd":"1231243134"
import Alamofire
import SwiftyJSON
private func downloadJson()
Alamofire.request("https://yourlinkdownloadjson/abc").responseJSON response in
debugPrint(response)
if let json = response.data
let data = JSON(data: json)
print("data\(data["codeAd"]["dateExpire"])")
print("data\(data["codeAd"]["codeRemoveAd"])")
【讨论】:
【参考方案8】:这是使用 Xcode 10.1 和 Swift 4 构建的
“Alamofire”(4.8.1) 和“SwiftyJSON”(4.2.0) 的完美组合。首先你应该安装两个 pod
pod 'Alamofire'
和pod 'SwiftyJSON'
JSON 格式的服务器响应:
"args": ,
"headers":
"Accept": "*/*",
"Accept-Encoding": "gzip;q=1.0, compress;q=0.5",
"Accept-Language": "en;q=1.0",
"Host": "httpbin.org",
"User-Agent": "AlamoFire TEST/1.0 (com.ighost.AlamoFire-TEST; build:1; iOS 12.1.0) Alamofire/4.8.1"
,
"origin": "200.55.140.181, 200.55.140.181",
"url": "https://httpbin.org/get"
在这种情况下,我想打印“主机”信息:“主机”:“httpbin.org”
Alamofire.request("https://httpbin.org/get").validate().responseJSON response in
switch response.result
case .success:
print("Validation Successful)")
if let json = response.data
do
let data = try JSON(data: json)
let str = data["headers"]["Host"]
print("DATA PARSED: \(str)")
catch
print("JSON Error")
case .failure(let error):
print(error)
保持冷静和快乐的代码?
【讨论】:
谢谢。我已经使用并重新格式化以满足我对项目的需求,我可以保证这仍然适用于 Swift 5。【参考方案9】:我找到了一种将 response.result.value(在 Alamofire responseJSON 闭包内)转换为我在我的应用程序中使用的 JSON 格式的方法。
我正在使用 Alamofire 3 和 Swift 2.2。
这是我使用的代码:
Alamofire.request(.POST, requestString,
parameters: parameters,
encoding: .JSON,
headers: headers).validate(statusCode: 200..<303)
.validate(contentType: ["application/json"])
.responseJSON (response) in
NSLog("response = \(response)")
switch response.result
case .Success:
guard let resultValue = response.result.value else
NSLog("Result value in response is nil")
completionHandler(response: nil)
return
let responseJSON = JSON(resultValue)
// I do any processing this function needs to do with the JSON here
// Here I call a completionHandler I wrote for the success case
break
case .Failure(let error):
NSLog("Error result: \(error)")
// Here I call a completionHandler I wrote for the failure case
return
【讨论】:
【参考方案10】:我通常在 iOS 中使用Gloss 库来序列化或反序列化 JSON。例如,我有如下所示的 JSON:
"ABDC":["AB":"qwerty","CD":"uiop"],["AB":"12334","CD":"asdf"]
首先,我在 Gloss 结构中对 JSON 数组进行建模:
Struct Struct_Name: Decodable
let IJ: String?
let KL: String?
init?(json: JSON)
self.IJ = "AB" <~~ json
self.KL = "CD" <~~ json
然后在 Alamofire responseJSON 中,我执行以下操作:
Alamofire.request(url, method: .get, paramters: parametersURL).validate(contentType: ["application/json"]).responseJSON response in
switch response.result
case .success (let data):
guard let value = data as? JSON,
let eventsArrayJSON = value["ABDC"] as? [JSON]
else fatalError()
let struct_name = [Struct_Name].from(jsonArray: eventsArrayJSON)//the JSON deserialization is done here, after this line you can do anything with your JSON
for i in 0 ..< Int((struct_name?.count)!)
print((struct_name?[i].IJ!)!)
print((struct_name?[i].KL!)!)
break
case .failure(let error):
print("Error: \(error)")
break
上面代码的输出:
qwerty
uiop
1234
asdf
【讨论】:
【参考方案11】:在 swift 5 中,我们确实喜欢使用 typealias 来完成。 Typlealias 只是用来清理代码而已。
typealias response = (Bool,Any?)->()
static func postCall(_ url : String, param : [String : Any],completion : @escaping response)
Alamofire.request(url, method: .post, parameters: param, encoding: JSONEncoding.default, headers: [:]).responseJSON (response) in
switch response.result
case .success(let JSON):
print("\n\n Success value and JSON: \(JSON)")
case .failure(let error):
print("\n\n Request failed with error: \(error)")
【讨论】:
【参考方案12】:简单的答案是让 AlamoFire 直接进行解码。
令人惊讶的是,您没有使用 .responseJSON,因为它返回一个无类型的 json 对象
相反,您将对象设为可解码 - 并要求 AF 直接对它们进行解码
我的 json 响应包含一个 Account 对象数组。我只关心 id 和 name 键(虽然还有更多)
struct Account:Codable
let id:Int
let name:String
那么简单
AF.request(url,
method: .get)
.responseDecodable(of:[Account].self) response in
switch response.result
case .success:
switch response.response?.statusCode
case 200:
//response.value is of type [Account]
default:
//handle other cases
case let .failure(error):
//probably the decoding failed because your json doesn't match the expected format
【讨论】:
【参考方案13】:let semaphore = DispatchSemaphore (value: 0)
var request = URLRequest(url: URL(string: Constant.localBaseurl2 + "compID")!,timeoutInterval: Double.infinity)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) data, response, error in
if let response = response
let nsHTTPResponse = response as! HTTPURLResponse
print(nsHTTPResponse)
if let error = error
print ("\(error)")
return
if let data = data
DispatchQueue.main.async
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase//or any other Decoder\
do
let jsonDecoder = JSONDecoder()
let memberRecord = try jsonDecoder.decode(COMPLAINTSVC.GetComplaints.self, from: data)
print(memberRecord.message)
for detailData in memberRecord.message
print(detailData)
catch
print(error.localizedDescription)
semaphore.signal()
task.resume()
semaphore.wait()
【讨论】:
OP 询问的是 Alamofire,而不是 URLRequest,所以这是题外话。此外,您的答案包含不相关的元素,似乎只是从现有代码库中随机复制的。请编辑并使其具体到这个问题。谢谢。【参考方案14】: pod 'Alamofire'
pod 'SwiftyJSON'
pod 'ReachabilitySwift'
import UIKit
import Alamofire
import SwiftyJSON
import SystemConfiguration
class WebServiceHelper: NSObject
typealias SuccessHandler = (JSON) -> Void
typealias FailureHandler = (Error) -> Void
// MARK: - Internet Connectivity
class func isConnectedToNetwork() -> Bool
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress,
$0.withMemoryRebound(to: sockaddr.self, capacity: 1)
SCNetworkReachabilityCreateWithAddress(nil, $0)
) else
return false
var flags: SCNetworkReachabilityFlags = []
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
return false
let isReachable = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)
return (isReachable && !needsConnection)
// MARK: - Helper Methods
class func getWebServiceCall(_ strURL : String, isShowLoader : Bool, success : @escaping SuccessHandler, failure : @escaping FailureHandler)
if isConnectedToNetwork()
print(strURL)
if isShowLoader == true
AppDelegate.getDelegate().showLoader()
Alamofire.request(strURL).responseJSON (resObj) -> Void in
print(resObj)
if resObj.result.isSuccess
let resJson = JSON(resObj.result.value!)
if isShowLoader == true
AppDelegate.getDelegate().dismissLoader()
debugPrint(resJson)
success(resJson)
if resObj.result.isFailure
let error : Error = resObj.result.error!
if isShowLoader == true
AppDelegate.getDelegate().dismissLoader()
debugPrint(error)
failure(error)
else
CommonMethods.showAlertWithError("", strMessage: Messages.NO_NETWORK, withTarget: (AppDelegate.getDelegate().window!.rootViewController)!)
class func getWebServiceCall(_ strURL : String, params : [String : AnyObject]?, isShowLoader : Bool, success : @escaping SuccessHandler, failure :@escaping FailureHandler)
if isConnectedToNetwork()
if isShowLoader == true
AppDelegate.getDelegate().showLoader()
Alamofire.request(strURL, method: .get, parameters: params, encoding: JSONEncoding.default, headers: nil).responseJSON(completionHandler: (resObj) -> Void in
print(resObj)
if resObj.result.isSuccess
let resJson = JSON(resObj.result.value!)
if isShowLoader == true
AppDelegate.getDelegate().dismissLoader()
success(resJson)
if resObj.result.isFailure
let error : Error = resObj.result.error!
if isShowLoader == true
AppDelegate.getDelegate().dismissLoader()
failure(error)
)
else
CommonMethods.showAlertWithError("", strMessage: Messages.NO_NETWORK, withTarget: (AppDelegate.getDelegate().window!.rootViewController)!)
class func postWebServiceCall(_ strURL : String, params : [String : AnyObject]?, isShowLoader : Bool, success : @escaping SuccessHandler, failure :@escaping FailureHandler)
if isConnectedToNetwork()
if isShowLoader == true
AppDelegate.getDelegate().showLoader()
Alamofire.request(strURL, method: .post, parameters: params, encoding: JSONEncoding.default, headers: nil).responseJSON(completionHandler: (resObj) -> Void in
print(resObj)
if resObj.result.isSuccess
let resJson = JSON(resObj.result.value!)
if isShowLoader == true
AppDelegate.getDelegate().dismissLoader()
success(resJson)
if resObj.result.isFailure
let error : Error = resObj.result.error!
if isShowLoader == true
AppDelegate.getDelegate().dismissLoader()
failure(error)
)
else
CommonMethods.showAlertWithError("", strMessage: Messages.NO_NETWORK, withTarget: (AppDelegate.getDelegate().window!.rootViewController)!)
class func postWebServiceCallWithImage(_ strURL : String, image : UIImage!, strImageParam : String, params : [String : AnyObject]?, isShowLoader : Bool, success : @escaping SuccessHandler, failure : @escaping FailureHandler)
if isConnectedToNetwork()
if isShowLoader == true
AppDelegate.getDelegate().showLoader()
Alamofire.upload(
multipartFormData: multipartFormData in
if let imageData = UIImageJPEGRepresentation(image, 0.5)
multipartFormData.append(imageData, withName: "Image.jpg")
for (key, value) in params!
let data = value as! String
multipartFormData.append(data.data(using: String.Encoding.utf8)!, withName: key)
print(multipartFormData)
,
to: strURL,
encodingCompletion: encodingResult in
switch encodingResult
case .success(let upload, _, _):
upload.responseJSON response in
debugPrint(response)
//let datastring = String(data: response, encoding: String.Encoding.utf8)
// print(datastring)
case .failure(let encodingError):
print(encodingError)
if isShowLoader == true
AppDelegate.getDelegate().dismissLoader()
let error : NSError = encodingError as NSError
failure(error)
switch encodingResult
case .success(let upload, _, _):
upload.responseJSON (response) -> Void in
if response.result.isSuccess
let resJson = JSON(response.result.value!)
if isShowLoader == true
AppDelegate.getDelegate().dismissLoader()
success(resJson)
if response.result.isFailure
let error : Error = response.result.error! as Error
if isShowLoader == true
AppDelegate.getDelegate().dismissLoader()
failure(error)
case .failure(let encodingError):
if isShowLoader == true
AppDelegate.getDelegate().dismissLoader()
let error : NSError = encodingError as NSError
failure(error)
)
else
CommonMethods.showAlertWithError("", strMessage: Messages.NO_NETWORK, withTarget: (AppDelegate.getDelegate().window!.rootViewController)!)
==================================
Call Method
let aParams : [String : String] = [
"ReqCode" : Constants.kRequestCodeLogin,
]
WebServiceHelper.postWebServiceCall(Constants.BaseURL, params: aParams as [String : AnyObject]?, isShowLoader: true, success: (responceObj) in
if "\(responceObj["RespCode"])" != "1"
let alert = UIAlertController(title: Constants.kAppName, message: "\(responceObj["RespMsg"])", preferredStyle: UIAlertControllerStyle.alert)
let OKAction = UIAlertAction(title: "OK", style: .default) (action:UIAlertAction!) in
alert.addAction(OKAction)
self.present(alert, animated: true, completion: nil)
else
let aParams : [String : String] = [
"Password" : self.dictAddLogin[AddLoginConstants.kPassword]!,
]
CommonMethods.saveCustomObject(aParams as AnyObject?, key: Constants.kLoginData)
, failure:
(error) in
CommonMethods.showAlertWithError(Constants.kALERT_TITLE_Error, strMessage: error.localizedDescription,withTarget: (AppDelegate.getDelegate().window!.rootViewController)!)
)
【讨论】:
对所有这些代码的解释会很有帮助。以上是关于如何在 Swift 中解析来自 Alamofire API 的 JSON 响应?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Swift 3 中使用 Alamofire 4 解析这个 json?
如何使用 Alamofire 在 Swift 3 中解析 JSON?
如何在swift中使用alamofire和swiftyjson解析分页url?
Alamofire 4 请求返回 NSArray,无法弄清楚如何在 Swift 3 中使用 SwiftyJSON 进行解析