Trying to wrap Codable response data from WebService
used cocoa pod
pod 'WebService', '~> 0.4'
var webServiceObject : WebService = WebService()
webServiceObject.sendRequest(URLString, parameters: parameters as NSDictionary?, requestType: .post, success: {response,data in
do{
// Handle data when request Success
let jsonDecoder = JSONDecoder()
do {
let result = try jsonDecoder.decode([ResponseModelValue].self, from: data as! Data)
print(response?.statusCode as Any)
print("Success Response Value", result)
}
} catch {
print(error)
}
}, failed: {
(response : HTTPURLResponse?, ResponseDict : Any?) in
print(response?.statusCode as Any)
print("Failed Response Dictionary", ResponseDict!)
// Handle data when request fails
}, encoded: false )
I got following error
Could not cast value of type '__NSDictionaryI' (0x10c81ab38) to 'NSData' (0x10c819620).
Can any one suggest me what I done wrong here, so I can parse proper response data with codable [ResponseModelValue]
After looking at that library, it appears that it will turn the response into a dictionary if possible and fall back to returning data.
https://github.com/kansaraprateek/WebService/blob/master/WebService/Classes/WebService.swift#L281
It doesn't appear like there is a way to configure that behaviour. The library was also created before Codable was created. You may need to reach out the library owner for a fix, fork the repo and fix it yourself, or switch to using URLSession since the code you posted is mostly the same as a URLSession call.
I'm using AFNetworking to retrieve weather info form openweathermap API.
let manager = AFHTTPSessionManager()
manager.requestSerializer = AFJSONRequestSerializer()
let url = "http://api.openweathermap.org/data/2.5/weather"
let params = ["lat": latitude,"lon": longitude,"cnt": 0]
manager.get(url, parameters: params,
success: {(operation: URLSessionDataTask,responseObject: AnyObject!) in print("JSON" + responseObject.description!) },
failure: {(operation: URLSessionDataTask?,error: Error) in print(error.localizedDescription)}
)
highlighting at responseObject.description indicated that 'Anyobject' is not a subtype of 'NSProxy'
If remove .description the error will disappear.
platform:xcode 8.3.2 swift:3
'Anyobject' is not a subtype of 'NSProxy'
First on of all the get method you are using is a deprecated one (I assume you have newest AFNetworking version). Please use the new one this way:
let manager = AFHTTPSessionManager()
manager.requestSerializer = AFJSONRequestSerializer()
let url = "http://api.openweathermap.org/data/2.5/weather"
let params = ["lat": 5.0,"lon": 5.0,"cnt": 0]
manager.get(url, parameters: params, progress: nil, success: { (operation, responseObject) in
if let responseObject = responseObject {
print(responseObject)
} else {
print("There is no response object") //assume parsing error for JSON
}
}) { (operation, error) in
print(error.localizedDescription)
}
As the last tip: if you are using Swift, better use Alamofire:
https://github.com/Alamofire/Alamofire
It supports lots of nice features coming from Swift and much nicer error handling. For example Alamofire treats parsing error as real errors and calls failure block, not success block like ANetworking.
Also allows you to easily integrate some JSON parsing libs like SwiftJSON
https://github.com/SwiftyJSON/SwiftyJSON
I read this about the URL Loading System:
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html#//apple_ref/doc/uid/10000165i
Can't figure out what class use and how to use it.
errorSreenshot
I suggest using a third party framework like Alamofire The native Swift networking is rather complicated, especially for beginners, because Swift is type-safe language and a JSON object can have nesting etc. that can only be seen after actually fetching of the object.
The good thing is that Alamofire can be easily installed with CocoaPods and it is actively being developed. Here is an example of a request made with Alamofire's 4.0 version for Swift 3 to fetch a JSON object from a url called yourUrl:
Alamofire.request("https://yourUrl").responseJSON { response in
print(response.request) // original URL request
print(response.response) // HTTP URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let json = response.result.value {
print("JSON: \(json)")
// do something with json here
}
}
You can then use another third party framework like SwiftyJSON to parse the JSON you retrieve - especially if it has a complicated structure. But sadly there is no update in sight for Swift 3 so I guess we have to wait and see how this pans out.
EDIT: There is an unofficial Swift 3 branch for SwiftyJSON, which can be installed with cocoapods (it works for me on iOS10/Swift 3):
pod 'SwiftyJSON', git: 'https://github.com/BaiduHiDeviOS/SwiftyJSON.git', branch: 'swift3'
Use following function to load URL.
fun loadURL()->void{
let defaultSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
var dataTask: NSURLSessionDataTask?
let url = NSURL(string: "URL TO LOAD")//Add url string here
dataTask = defaultSession.dataTaskWithURL(url!) {
data, response, error in
dispatch_async(dispatch_get_main_queue()) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
if let error = error {
print(error.localizedDescription)
} else if let httpResponse = response as? NSHTTPURLResponse {
if httpResponse.statusCode == 200 {
print(data);
//Process data here..
}
}
}
dataTask?.resume()
}
You can use build in NSJSonSerialization class to convert NSdata into NSDictionary and then parse Dictionary to extract values.Your parsing logic will be added //Process data here.. in place of this comment in above code base.
The code works perfectly. The problem is that, after trying for a while, I cannot figure out how to make my program process a second link of different JSON data.
Here is my viewDidLoad where everything goes on:
override func viewDidLoad() {
super.viewDidLoad()
var err: NSError?
let urlPath: String = "https://na.api.pvp.net/api/lol/na/v1.4/summoner/by-name/" + searchFieldDataPassed + "?api_key=(removed my private api key for obvious reasons"
var url: NSURL = NSURL(string: urlPath)!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { data, response, error in
// cast response as NSHTTPURLResponse and switch on statusCode if you like
if let httpResponse = response as? NSHTTPURLResponse { switch httpResponse.statusCode { case 200..<300: println("OK") default: println("Not OK") } }
// parse JSON using NSJSONSerialization if you've got data
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as? NSDictionary,
let include = jsonResult.objectForKey(self.searchFieldDataPassed) as? NSDictionary {
if let summLevel = include[ "summonerLevel" ] as? NSNumber {
dispatch_async(dispatch_get_main_queue()) {
self.summonerLevel.text = "\(summLevel.integerValue)"
println("summoner level: \(summLevel.integerValue)")
}
}
if let profIconId = include[ "profileIconId" ] as? NSNumber {
dispatch_async(dispatch_get_main_queue()) {
self.profileIconId.text = "\(profIconId.integerValue)"
println("profile icon id: \(profIconId.integerValue)")
}
}
if let idNum = include [ "id" ] as? NSNumber {
dispatch_async(dispatch_get_main_queue()) {
self.idNumber = idNum
println("id number: \(self.idNumber)")
}
}
}
// spawn off another network call here if you like
}
task.resume()
}
That is from my secondViewController where all the processing goes on for JSON and then is displayed.
Here is the JSON data that I'm processing (for the first JSON parsing):
{"soon2challenger":{"id":43993167,"name":"soon2challenger","profileIconId":844,"summonerLevel":30,"revisionDate":1435549418000}}
All of that works fine, now, I want to process this JSON data which actually takes the id from the first parsed JSON data and uses it in the link to process more data, which I would like to output, part of it, to the screen.
Second JSON data:
{"summonerId":43993167,"playerStatSummaries":[{"playerStatSummaryType":"AramUnranked5x5","wins":25,"modifyDate":1423007927000,"aggregatedStats":{"totalChampionKills":676,"totalTurretsKilled":20,"totalAssists":991}},{"playerStatSummaryType":"CAP5x5","wins":15,"modifyDate":1429065922000,"aggregatedStats":{"totalChampionKills":312,"totalMinionKills":4885,"totalTurretsKilled":31,"totalNeutralMinionsKilled":511,"totalAssists":216}},{"playerStatSummaryType":"CoopVsAI","wins":28,"modifyDate":1421882181000,"aggregatedStats":{"totalChampionKills":266,"totalMinionKills":2802,"totalTurretsKilled":50,"totalNeutralMinionsKilled":385,"totalAssists":164,"maxChampionsKilled":0,"averageNodeCapture":0,"averageNodeNeutralize":0,"averageTeamObjective":0,"averageTotalPlayerScore":49,"averageCombatPlayerScore":0,"averageObjectivePlayerScore":49,"averageNodeCaptureAssist":0,"averageNodeNeutralizeAssist":0,"maxNodeCapture":0,"maxNodeNeutralize":0,"maxTeamObjective":0,"maxTotalPlayerScore":49,"maxCombatPlayerScore":0,"maxObjectivePlayerScore":49,"maxNodeCaptureAssist":0,"maxNodeNeutralizeAssist":0,"totalNodeNeutralize":0,"totalNodeCapture":0,"averageChampionsKilled":0,"averageNumDeaths":0,"averageAssists":0,"maxAssists":0}},{"playerStatSummaryType":"CoopVsAI3x3","wins":15,"modifyDate":1421882181000,"aggregatedStats":{"totalChampionKills":140,"totalMinionKills":1114,"totalTurretsKilled":9,"totalNeutralMinionsKilled":449,"totalAssists":91}},{"playerStatSummaryType":"OdinUnranked","wins":1,"modifyDate":1421882181000,"aggregatedStats":{"totalChampionKills":31,"totalAssists":45,"maxChampionsKilled":10,"averageNodeCapture":4,"averageNodeNeutralize":4,"averageTeamObjective":0,"averageTotalPlayerScore":843,"averageCombatPlayerScore":268,"averageObjectivePlayerScore":575,"averageNodeCaptureAssist":3,"averageNodeNeutralizeAssist":1,"maxNodeCapture":6,"maxNodeNeutralize":7,"maxTeamObjective":2,"maxTotalPlayerScore":1468,"maxCombatPlayerScore":529,"maxObjectivePlayerScore":939,"maxNodeCaptureAssist":5,"maxNodeNeutralizeAssist":2,"totalNodeNeutralize":22,"totalNodeCapture":25,"averageChampionsKilled":5,"averageNumDeaths":5,"averageAssists":8,"maxAssists":19}},{"playerStatSummaryType":"RankedSolo5x5","wins":116,"losses":120,"modifyDate":1433630047000,"aggregatedStats":{"totalChampionKills":1699,"totalMinionKills":33431,"totalTurretsKilled":219,"totalNeutralMinionsKilled":6501,"totalAssists":1969}},{"playerStatSummaryType":"RankedTeam3x3","wins":0,"losses":0,"modifyDate":1377726216000,"aggregatedStats":{}},{"playerStatSummaryType":"RankedTeam5x5","wins":3,"losses":0,"modifyDate":1383784473000,"aggregatedStats":{"totalChampionKills":28,"totalMinionKills":636,"totalTurretsKilled":6,"totalNeutralMinionsKilled":101,"totalAssists":41}},{"playerStatSummaryType":"Unranked3x3","wins":9,"modifyDate":1421882181000,"aggregatedStats":{"totalChampionKills":90,"totalMinionKills":1427,"totalTurretsKilled":11,"totalNeutralMinionsKilled":428,"totalAssists":105}},{"playerStatSummaryType":"URF","wins":4,"modifyDate":1435024847000,"aggregatedStats":{"totalChampionKills":68,"totalMinionKills":642,"totalTurretsKilled":14,"totalNeutralMinionsKilled":182,"totalAssists":55}},{"playerStatSummaryType":"Unranked","wins":566,"modifyDate":1435549418000,"aggregatedStats":{"totalChampionKills":8419,"totalMinionKills":128213,"totalTurretsKilled":960,"totalNeutralMinionsKilled":26117,"totalAssists":7812}}]}
Heres the link of the second JSON data I want to parse (just adding it, could be useful, but not sure):
https://na.api.pvp.net/api/lol/na/v1.3/stats/by-summoner/43993167/summary?season=SEASON2015&api_key=(took-out-my-private-api-key-for-obvious-reasons)
The link doesn't work because I have to keep my api key private to myself, but the JSON data that it displays is right above the link, which is the what it would result if you were to use the link with the api key.
Just to restate, I would like to process the second part (above of this) of JSON data, but I do not understand how to process multiple links of JSON. I have the first JSON data parsed, but am unable to parse the second JSON data.
I believe Apple is deprecating NSURLConnection. Take a look at NSURLSession. Using it, you can pass in a completion block that takes three arguments: NSData?, NSURLResponse?, and NSError?. The data object contains the JSON you can pass into the JSON serializer. After that, if you need to make another network call, just call it from inside the completion block with another NSURLSession data task. Alamofire is a great framework, but sometimes you don't need everything it provides, and it adds complexity into your app that if something goes wrong or doesn't behave the way you intend/understand, you may not fully understand why. If you want to keep it simple and under your control, use NSURLSession.
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { data, response, error in
// cast response as NSHTTPURLResponse and switch on statusCode if you like
// parse JSON using NSJSONSerialization if you've got data
// spawn off another network call here if you like
}
task.resume() // or in Swift 2, task?.resume()
First, i would totally prefer using some common frameworks for http requests - expecially if youre new in swift. For example here with alamofire.
https://github.com/Alamofire/Alamofire
There is also a version with integrated SwiftyJSON, so you are able to parse JSON Responses very easily.
https://github.com/SwiftyJSON/Alamofire-SwiftyJSON
So if you want to make a request, use this:
Alamofire.request(.GET, "http://httpbin.org/get")
.responseJSON { (_, _, json, _) in
var json = JSON(json)
// get the id out (depends on your structure of JSON):
let id = json["id"].int
}
Now you are able to perform a second Request (with the same Code) - Read the Documentation, how to make different Requests (like with POST) and add Parameters.
If you want to use Segues, so you want to load more data from the ID in another ViewController, you can use Segues to push the data to a second ViewController, and Load the new Content from JSON when the new ViewController is initialised.
Check out this how to send data through segues:
Sending data with Segue with Swift
I'm trying to use the Yoda API and send a request using the Alamofire Swift framework. I know that the API is correctly working, as I have tested the endpoint with my Mashape API key multiple times. I can also see that the requests are being sent (homepage of Mashape under my application). However my JSON response is always nil.
func handleRequest(words:String){
var saying = words.stringByReplacingOccurrencesOfString(" ", withString: "+");
saying = "?sentence=" + saying;
let url = NSURL(string: (baseURL+saying));
println(url);
var response:String;
Alamofire.Manager.sharedInstance.session.configuration.HTTPAdditionalHeaders = additionalHeaders;
Alamofire.request(.GET, url!).responseJSON { (_, _, JSON, _) in
println(JSON);
}
}
The words string can be "This is my first sentence" and it will automatically replace the spaces with "+" as per the API spec. Please Ignore the multiple println statements, they are just for debugging.
This is just proof of concept code, its purposely not doing much error checking and isn't pretty for that reason. If you have any suggestions I would appreciate them.
For some reason it's an issue I've too with the Alamofire request for JSON. It is the way I handle the JSON requests using Alamofire :
Alamofire.request(.GET, urlTo, parameters: nil, encoding: .URL).responseString(completionHandler: {
(request: NSURLRequest, response: NSHTTPURLResponse?, responseBody: String?, error: NSError?) -> Void in
// Convert the response to NSData to handle with SwiftyJSON
if let data = (responseBody as NSString).dataUsingEncoding(NSUTF8StringEncoding) {
let json = JSON(data: data)
println(json)
}
})
I strongly recommend you using SwiftyJSON to manage the JSON in a better and easy way, it's up to you.
I hope this help you.
Alamofire request have several method for handle response. Try to handle data response and convert it to String. Confirm that response JSON is normal.
Alamofire.request(.GET, url!).response { (_, _, data, error) in
let str = NSString(data: data, encoding: NSUTF8StringEncoding)
println(str)
println(error)
}
Also checkout error while parsing JSON data.