Add elements from SwiftyJSON to URL array in Swift - ios

I'm retrieving a list of URL images using Alamofire. The response is in JSON And I have used SwiftyJSON to parse and print each element. I want the URLs to be added into a URL array. Below is the code I have used
var newArray = [URL(string: "http://www.tummyvision.com/users/uploads/gijovarghese141#gmail.com/photos/4.jpg")]
Alamofire.request("http://www.tummyvision.com/users/login/get-images.php", parameters: parameters).responseData { response in
let json = JSON(data: response.result.value!)
for i in 0..<json.count
{
print(json[i]) // prints the correct url
self.urlArray.append(json[i])
}
}
But it is giving me the following error:

Try to use arrayValue property of JSON to access array also you need to convert String Url to URL object before adding it into Array of URL.
if let urls = json.arrayValue {
for url in urls {
self.urlArray.append(URL(string:url))
}
}

Related

download Image and save it json using SwiftyJSON

I have json in below format which I am fetching from server and parsing using SwiftyJSON.
{
name: "Ganesh"
imageURL:"www.abc.com/image.png"
}
I am downloading image using below code :
do{
let myData = try Data(contentsOf: url)
}catch{
Print("error")
}
Note: "url" contains url from json which is converted from string to URL
I want to save this "myData" in same json above with different key and access the same in future.
I am trying to save myData in json using SwiftyJSON method :
responseJSON["image"] = try JSON(data: myData)
Error which I am receiving :
"if Error while converting data into json The data couldn’t be read because it isn’t in the correct format."
I am not getting what is the problem?
Image is present at that url. if I convert myData into UIImage and If I assign it on UIImageView I can see it.
If you want to save an image in JSON, the best way would be to convert Data to Base64 string
if let base64encodedString = myData.base64EncodedString(){
responseJSON["image"] = base64encodedString
}
To restore image, try this
guard let base64encodedString = responseJSON["image"] as? String else { return }
guard let imageData = Data(base64Encoded: base64encodedString) else { return }
let image = UIImage(data: imageData)
Although Base64 - encoded images take approximately 33% more space than raw data, they are web and database safe - base64 strings contain neither control characters, nor quotes, and can be transferred as parameter in URL query strings.

How to remove xml tags before send to the json parser in swift

I want to use JSON data in my app. So I am using this webservice calling method to convert my json data to an array.
func getData(path: String, completion: (dataArray: NSArray)->()) {
let semaphore = dispatch_semaphore_create(0)
// var datalistArray = NSArray()
let baseUrl = NSBundle.mainBundle().infoDictionary!["BaseURL"] as! String
let fullUrl = "\(baseUrl)\(path)"
print("FULL URL-----HTTPClient \(fullUrl)")
guard let endpoint = NSURL(string:fullUrl) else {
print("Error creating endpoint")
return
}
let request = NSMutableURLRequest(URL: endpoint)
NSURLSession.sharedSession().dataTaskWithRequest(request,completionHandler: {(data,response,error) in
do {
guard let data = data else {
throw JSONError.NoData
}
guard let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSArray else {//NSJSONReadingOptions.AllowFragments
throw JSONError.ConversionFailed
}
print(json)
if let data_list:NSArray = json {
completion(dataArray: data_list)
dispatch_semaphore_signal(semaphore);
}
}catch let error as JSONError {
print(error.rawValue)
} catch let error as NSError {
print(error.debugDescription)
}
}) .resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
But now my service sending json data within xml tags like <string xmlns="http://tempuri.org/">json data</string so I am getting an exception when I try to convert my json data. The exception is this.
Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}
What should I change in my code to remove those tags before sending to json parser?
Please help me.
Thanks
I think your response that you get from server is in xml format not in json. If it is in xml format then you must do xml parsing instead of json parsing.
NSJSONSerialization.JSONObjectWithData is json parsing that give json object from data (data in json format).
But if you getting response in xml format from server then you should use NSXMLParser to parse the data.
If you don't have much idea about it then you can refer tutorial like
XML Parsing using NSXMLParse in Swift by The appguruz or can use third party libraries.

Alamofire JSON Request not pulling the data from a server

Im using Alamofire to pull a JSON file from a server (http://midlandgates.co.uk/JSON/reliveCacheData.json). To do this I have an Alamofire Request function which should pull the data down and write it to a class called JSONDataClass.
Alamofire Request
Alamofire.request(.GET, "http://midlandgates.co.uk/JSON/reliveCacheData.json")
.response { request, response, data, error in
if let data = data {
let json = JSON(data:data)
for locationData in json {
let locationDataJSON = JSONDataClass(json: locationData.1)
self.cacheData.append(locationDataJSON)
}
for title in self.cacheData {
print(title.memoryTitle)
}
}
}
However my printLn isn't printing the data from the JSON File which indicates there is a problem with either the request or the class. However I'm new to swift and can't seem to work out the problem, all help is appreciated!
Class
import Foundation
import CoreLocation
import SwiftyJSON
class JSONDataClass {
//Location MetaData
var postUser: String!
var memoryTitle: String!
var memoryDescription: String!
var memoryType: String!
var memoryEmotion: String!
var taggedFriends: String!
//Location LocationalData
var memoryLocation: CLLocationCoordinate2D
//MultiMedia AddressData
var media1: String!
var media2: String!
var media3: String!
var media4: String!
var media5: String!
//Writing to varibles
init(json: JSON) {
postUser = json["user"].stringValue
memoryTitle = json["title"].stringValue
memoryDescription = json["description"].stringValue
memoryType = json["type"].stringValue
memoryEmotion = json["emotion"].stringValue
taggedFriends = json["friends"].stringValue
memoryLocation = CLLocationCoordinate2D(latitude: json["latitude"].doubleValue, longitude: json["longitude"].doubleValue)
media1 = json["media1"].stringValue
media2 = json["media2"].stringValue
media3 = json["media3"].stringValue
media4 = json["media4"].stringValue
media5 = json["media5"].stringValue
}
}
(Note: the author of the JSON content has fixed his JSON based on my answer - my answer was correct at the time of this post).
The problem is that you've got invalid JSON coming back from the server.
I switched your SwiftyJSON code out and wrapped it in a try-catch which illuminated the problem:
Alamofire.request(.GET, "http://midlandgates.co.uk/JSON/reliveCacheData.json")
.response { request, response, data, error in
//print("status \(response)")
do {
let myData = try NSJSONSerialization.JSONObjectWithData(data!,
options: .MutableLeaves)
print(myData)
} catch let error {
print(error)
}
}
And I get the following error:
2015-12-30 13:47:06.129 {{ignore}}[10185:2174510] Unknown class log in Interface Builder file.
Error Domain=NSCocoaErrorDomain Code=3840 "Unescaped control character around character 961."
UserInfo={NSDebugDescription=Unescaped control character around
character 961.}
This error basically means that you have invalid JSON coming back from the server.
Make sure your json is valid by running it through JSONLint:
http://jsonlint.com
Are you new to debuggers and breakpoints?
Set a breakpoint in your response closure (for example, in your if let data = data { line) and step through your code to see if it does what you expect at every stage. Maybe error is set? Maybe the if let data = data { conditional failed (you're not doing anything in an else to log the failure, so how could you know?)...
After I checked the discussion and the data provided by the server from you link, I can say, that your trouble is how to deal with your JSON (class, or struct, or enum??)
Did you follow some tutorial from SwiftyJSON? While your init(json: JSON) in class JSONDataClass seems to accept some JSON object (aka dictionary), in reality your json is an JSON array! Check SwiftyJSON documentation and take in your account, that you received an array.
try this instead:
for d in json {
let locationDataJSON = JSONDataClass(json: d)
self.cacheData.append(locationDataJSON)
}
and see, that locationDataJSON is NOT location data but one json object from the received array. or just remove .1 in locationData.1
For example:
Alamofire.request(.GET, "http://midlandgates.co.uk/JSON/reliveCacheData.json")
.response { request, response, data, error in
if let data = data {
let json = JSON(data:data)
for locationData in json {
let locationDataJSON = JSONDataClass(json: locationData)
self.cacheData.append(locationDataJSON)
}
for title in self.cacheData {
print(title.memoryTitle)
}
}
}

How can I process multiple links of JSON data?

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

How can I use swiftyJSON dictionaryValue as a usable string for a UILabel?

I have a makeRequest() method inside a UITableViewController with the following code:
func makeRequest() {
Alamofire.request(.GET, self.foursquareEndpointURL, parameters: [
//"VENUE_ID" : self.foursquareVenueID,
"client_id" : self.foursquareClientID,
"client_secret" : self.foursquareClientSecret,
"v" : "20140806"
])
.responseJSON(options: nil) { (_, _, data, error) -> Void in
if error != nil {
println(error?.localizedDescription)
} else if let data: AnyObject = data {
let jObj = JSON(data)
if let venue = jObj["response"]["venue"].dictionaryValue as [String: JSON]? {
self.responseitems = jObj
println("venue is: \(venue)")
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData() // Update UI
}
}
}
}
also keep in mind that I have a property var responseitems:JSON = []
println("venue is: \(venue)") prints a nice looking response to console, so I know that is working correctly...
I also have a custom UITableViewCell class with a bindData() method with the following code:
func bindData() {
println("VenueDetailHeaderCell data did set")
self.venueDetailTitleLabel.text = self.headerInfo?["name"].stringValue
let labelData = self.headerInfo?["name"].stringValue
println("labelData is: \(labelData)")
}
As you can see, I am attempting to set a UILabel's text to the ["name"].stringValue in the JSON response. However, when I println("labelData is: \(labelData)") I get console output of labelData is: Optional("") which is obviously empty.
Here's a screenshot of what I'm trying to grab
What am I doing wrong here and how can I grab the name of the venue and assign my UILabel to it?
UPDATE:
I tried the following code
let labelData = self.headerInfo?["name"].error
println("labelData is: \(labelData)")
And get a console output of: "Error Domain=SwiftyJSONErrorDomain Code=901 "Array[0] failure, It is not an array" UserInfo=0x7fd6d9f7dc10 {NSLocalizedDescription=Array[0] failure, It is not an array}" If that is of use to anyone. I am really confused here... Any ideas?
The problem is that the headerInfo value is an error JSON object, because you're trying to access a dictionary with an integer index.
Note that var responseitems:JSON = [] does not create an array object. SwiftyJSON has auto-assignment-constructors (I'm new to swift, so not sure what the correct swift terminology is)... see this initialiser in the SwiftyJSON.swift source code:
extension JSON: ArrayLiteralConvertible {
public init(arrayLiteral elements: AnyObject...) {
self.init(elements)
}
}
What this means is that when you do var responseitems:JSON = [] you are not creating an array, you are creating a JSON object that is constructed with an empty array using the above init method. Then when you do self.responseitems = jObj you are re-assigning that responseitems variable to a JSON object with a dictionary in it. Therefore self.responseitems[0] is invalid.
Also note that with SwiftyJSON, there is no such thing as an optional JSON object. I notice in your comment you say that you do var headerInfo:JSON? ... - it's not possible to have an optional JSON.
var headerInfo: JSON = nil
The above is possible - this uses another auto-initialiser that initialises a valid JSON object that represents the JSON null value.
So, how to fix it?
When you assign headerInfo do it like this:
let headerInfo = self.responseitems["response"]["venue"]
And now in bindData you can do:
self.venueDetailTitleLabel.text = self.headerInfo["name"].stringValue
Note that all of the above assumes Swift 1.2 and SwiftyJSON >= 2.2 - also after you've understood the above and corrected the issue, you will probably want to refactor the code a bit to reflect the corrected understanding of the data-model.
The way to parse is the next
element: JSONValue //Something with JSONValue
if let title = element["name"]?.string {
cell.title.text = title
}

Resources