I am parsing JSON and appending the data to an array, and while the array contains the correct number of elements, it is just the same element over and over, whatever the last one added was. Here is the code I am using:
if (statusCode == 200) {
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
if let ns = json as? NSArray{
for ns in ns{
if let name = ns["name"] as? String{
if let number = ns["number"] as? Int{
if let cn = ns["cyclenumber"] as? Int{
if let url = ns["url"] as? String{
self.c.name = name
self.c.number = number
self.c.cycleNumber = cn
self.c.url = url
self.n.array.append(self.c)
}
}
}
}
}
}
}catch {
print("Error with Json: \(error)")
}
}
When I print the array, it just prints however many elements were added, but they are all duplicates of the last element added.
The problem is that you keep appending the sane instance - namely, self.c. Since the type of c is a class, not struct, no copying is going on; the same reference is added to the array over and over again.
You can fix this problem by making c's type a struct, or by assigning a new c on each iteration of the loop:
if let url = ns["url"] as? String {
var c = TypeOfC() // Make a new instance
c.name = name
c.number = number
c.cycleNumber = cn
c.url = url
self.n.array.append(c)
}
Note that c is no longer a member of self. Since you are changing c inside a loop, making it a member was very likely a mistake in the first place.
Answer's already been given, but I thought I should clean up your code a bit :)
guard let data = data where statusCode == 200 else {
return
}
do{
let json = try NSJSONSerialization.JSONObjectWithData(data, options:.AllowFragments)
if let ns = json as? NSArray{
for ns in ns{
if let name = ns["name"] as? String, number = ns["number"] as? Int,
cn = ns["cyclenumber"] as? Int, url = ns["url"] as? String{
self.c.name = name
self.c.number = number
self.c.cycleNumber = cn
self.c.url = url
self.n.array.append(self.c)
}
}
}
}catch {
print("Error with Json: \(error)")
}
Related
I wrote an API which returns the username and amount and at what time the transaction was placed. I got the response from the backend as an array of objects and I stored it as NSArray in client side. And I want to attach that response to labels so I converted that NSArray into String and In Database some fields are empty so the response returns the null values whenever the response returns the null values I am getting this error like "Could not cast the value of NSNUll to NSString". What I thought is replace the null value in that array with string. I tried so much but it always shows the same error how to resolve that problem. This is my code :
let response = JSON as! NSDictionary
//example if there is an id
let deyaPaybalance = response.object(forKey: "Details")
print(deyaPaybalance!)
let Amount1:[Double] = (response.object(forKey: "Amount")) as! [Double]
print("Amount is",Amount1)
for ele:Double in Amount1 {
self.amo += [String(ele)]
}
print("amount is in string",self.amo)
let time = response.object(forKey: "Time") as! NSArray
print("time is", time)
let id = response.object(forKey: "TransactionID")
print("id is",id!)
let name:NSArray = response.object(forKey: "RName") as!NSArray
print("name is",name)
// let len = name.count
for (object) in name.enumerated() {
if let i = name.index(of: "null") {
print("hey it's nnull")
//name.index(of: "null")
}
else {
print("hello")
}
}
print("name",name)
// It is used to get the date from the time tsamp
for element in time {
let ele = element
let formatter = ISO8601DateFormatter()
//print("date is",date1!)
formatter.formatOptions = [.withFullDate,
.withTime,
.withDashSeparatorInDate,
.withColonSeparatorInTime]
self.date2 = formatter.date(from: ele as! String)!
self.anotherFormatter.dateFormat = "MMM dd yyyy, h:mm a" // It is used to to show the date in th form of month year and time
self.anotherFormatter.string(from: self.date2)
let b = self.anotherFormatter.string(from: self.date2)
let final = b.replacingOccurrences(of: ",", with: " ")
let trimmedString = final.trimmingCharacters(in: .whitespaces)
self.dt += [trimmedString] // it is stored the final date and time
print("final tim is",trimmedString)
}
// End of the for loop
print(self.dt)
let contactViewController = self.storyboard?.instantiateViewController(withIdentifier: "TransactionDetails")as! TransactionDetails
contactViewController.method = deyaPaybalance as! [String]
contactViewController.amount = self.amo
contactViewController.timestamp = self.dt
contactViewController.transactionid = id as! [String]
contactViewController.name = name as! [String]// I am getting error here.
self.navigationController?.pushViewController(contactViewController, animated: true)
self.dismiss(animated: false, completion: nil)
UIApplication.shared.endIgnoringInteractionEvents()
You need to use like this to handle null in swift.
if let arr_name = name as? [String]{
contactViewController.name = arr_name
}else{
contactViewController.name = []
}
For replacing nil value in [String]
var name = ["a",nil,"3"]
if let nil_index = name.index(of: nil){
name[nil_index] = "empty"
}
print(name as! [String]) // Output is ["a", "empty", "3"]
I am trying to parse the JSON below (actual data is 20x the format listed)
{
message = "";
result = (
{
Ask = "4.8e-05";
BaseVolume = "32.61025363";
Bid = "4.695e-05";
Created = "2017-06-06T01:22:35.727";
High = "5.44e-05";
Last = "4.69e-05";
Low = "4.683e-05";
MarketName = "BTC-1ST";
OpenBuyOrders = 293;
OpenSellOrders = 4186;
PrevDay = "4.76e-05";
TimeStamp = "2018-02-20T00:00:31.863";
Volume = "662575.93818332";
},
This is the code that I have right now. It successfully prints the value "Last" to the console but when I incorporate the Dispatch.Queue, I get a Thread 1: signal SIGBRT not printing the value to the label.
let myJson = try JSONSerialization.jsonObject(with: content) as! [String:Any]
if let info = myJson["result"] as! [[String:Any]]?
{
for i in 0..<20 {
if i == 1
{
if let dict = info[i] as? [String:Any]
{
if let price = dict["Last"]
{
print(price)
//DispatchQueue.main.async
//{
// self.label1.text = price as String
//}
}
}
}
Any help is greatly appreciated!
Most likely your self.label1 outlet isn't connected. Fix that connection.
You should also update the if let that gets the value for the "Last" key as follows:
if let price = dict["Last"] as? String{
print(price)
DispatchQueue.main.async {
self.label1.text = price
}
}
There is some other cleanup you can do as well:
if let myJson = try JSONSerialization.jsonObject(with: content) as? [String:Any] {
if let info = myJson["result"] as? [[String:Any]] {
for (index, dict) in info.enumerated() {
if index == 1 {
if let price = dict["Last"] as? String {
print(price)
DispatchQueue.main.async {
self.label1.text = price
}
} // else no "Last" or not a String
}
}
} // else "result" doesn't contain expected array of dictionary
} // else content isn't a valid JSON dictionary
Avoid all of those forced casts. Especially avoid force casting to an optional.
JSON doesn't use the = sign or the semicolon. Change every = to a colon and every semicolon to a comma, so that
Ask = "4.8e-05";
BaseVolume = "32.61025363";
Bid = "4.695e-05";
Becomes
Ask: "4.8e-05",
BaseVolume: "32.61025363",
Bid: "4.695e-05",
I can't retrieve and print the jobDate data. what's wrong my code?
let retrievetime = UserDefaults().value(forKey: "retrieve")as? NSDictionary
print(retrievetime!)
if let job = retrievetime!["jobs"] as? [String:Any], let jobTitle = job["jobDate"] as? String {
self.navigationItem.title = jobTitle
print(jobTitle)
}
//self.navigationItem.title = "Test"
print retrieve time! json output:
{
jobs =({
jobDate = "2017-08-31";
jobEndTime = 1504144800;
jobID = 87;
jobTime = 1504137600;
});
message = "Retrieve Sucessfully";
result = success;
}
First of all use use the standard singleton instance and optional bindings to safely get data from UserDefaults – unless you registered the key/value pairs.
Second of all never use value(forKey with UserDefaults and never use NSDictionary in Swift unless the compiler tells you to do.
Finally as mentioned in the comments the value for key jobs – as the plural form implies – is an array, you have to get the first object of the array
if let retrievetime = UserDefaults.standard.object(forKey: "retrieve") as? [String:Any] {
print(retrievetime)
if let jobs = retrievetime["jobs"] as? [[String:Any]],
let job = jobs.first,
let jobTitle = job["jobDate"] as? String {
self.navigationItem.title = jobTitle
print(jobTitle)
}
}
let retrievetime = UserDefaults().value(forKey: "retrieve")as? NSDictionary
print(retrievetime!)
if let job = retrievetime!["jobs"] as? [String:Any], let jobTitle = ((retrievetime!["jobs"] as? [String:Any])[0] as? NSDictionary)["jobDate"] as? String {
self.navigationItem.title = jobTitle
print(jobTitle)
}
//self.navigationItem.title = "Test"
My api query is returning several values in an array (as below), which I need to use for further functions. How do I retrieve the value 60, which is nested?
My code eg let uid = value["uid"] as? String works well to return uid and name.
But for let rest = value["field_resting_bpm"] as? String it returns nil.
How do I correct this line to return the nested value '60'?:
let rest = value["field_resting_bpm"] as? String'
the api query is:
let credentialData = "\(user):\(password)".dataUsingEncoding(NSUTF8StringEncoding)!
let base64Credentials = credentialData.base64EncodedStringWithOptions([])
let headers = ["Authorization": "Basic \(base64Credentials)"]
var checkUserEndpoint: String = "https://example.site/ios1/user/1.json"
Alamofire.request(.GET, checkUserEndpoint, parameters: nil, headers: headers, encoding: .JSON)
.responseJSON { response in
guard response.result.error == nil else {
print("ran alamofire")
//got an error in getting the data, need to handle it
print("error calling GET")
print(response.result.error!)
return
}
guard let value = response.result.value else {
print("no result data received when calling GET")
return
}
// return UID
print("ran alamofire")
var datareturned = JSON(value)
print("VALUE: \(value)")
it returns this in my console:
uid = 1;
name = "Guest User";
"field_resting_bpm" = {
und = (
{
value = 60;
}
);
UPDATE: this field is an Integer in Drupal user account settings. I have added a text field (so it should return a string), named field_rest_bpm_string, also for testing
the json on the site returns:
"field_resting_bpm":{"und":[{"value":"60"}]},"field_rest_bpm_string":{"und":[{"value":"65","format":null,"safe_value":"65"}]}
NOTE: Code is in Swift 3 but you can easily convert that in swift 2. SwiftyJSON version code is same in 2 and 3.
If you are using SwiftyJSON then things are pretty much simpler
let value = datareturned["field_resting_bpm"]["und"][0]["value"].stringValue
print(value)
If you are not using SwiftyJSON
let rest = value["field_resting_bpm"] as? NSDictionary
let und = (rest?.value(forKey: "und") as! NSArray).object(at: 0) as! NSDictionary
let yourValue = und.value(forKey: "value") as! String
Something like this.
This is My Code:
urll = NSURL(string: "http://xxxxxxxxxxx.com/api/?slider=uij6sdnb")
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(urll) {(NSData, response, error) -> Void in
do {
let records = try NSJSONSerialization.JSONObjectWithData(NSData!, options: NSJSONReadingOptions.MutableContainers) as! NSArray
for record in records {
// let urlid = Int(record["slide_id"] as! String)
let urimage = record["slide_url"] as! String
self.urls = [urimage]
print(self.urls.count)
}
}
catch {
print("Json Error")
}
}
task.resume()
When I Print :
print(urimage)
it gaves me 4 url like this:
http://sdkladlkasjd1.jpg
http://sdkladlkasjd2.jpg
http://sdkladlkasjd3.jpg
http://sdkladlkasjd4.jpg
When I print:
print(urimage[1])
It gaves me :
'subscript' is unavailable: cannot subscript String with an Int, see the documentation comment for discussion
When i put it in another value :
var urls = [String]()
self.urls = [urimage]
and I print:
print(self.urls.count)
it gaves me
1
1
1
1
How on earch I can access one of this urls !?
I want to Show them on imageview but I can !
As Julian Kniephoff rightly mentioned, you are printing each URL in the for loop, thus you cannot access one particular one. However, there is also another issue, in that you are replacing the urls array with the latest url each time.
To solve this, simply replace the line self.urls = [urimage] with self.urls.append(urimage).
You can then access a particular image outside the for loop by doing something like self.urls[1].
This is also why printing the count of the array returns 1, since each time around you are setting the array to just the one latest element in the loop.
In the end, your code may look something like this
url = NSURL(string: "http://xxxxxxxxxxx.com/api/?slider=uij6sdnb")
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) {(data, response, error) -> Void in
do {
let records = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSArray
for record in records {
//let urlid = Int(record["slide_id"] as! String)
let urimage = record["slide_url"] as! String
self.urls.append(urimage)
}
print(self.urls[1]) //Prints http://sdkladlkasjd2.jpg
}
catch {
print("Json Error")
}
//print(self.urls[1])
}
task.resume()