Values are not updating in my text label from api calling - ios

I have one api calling, and I am passing one parameter value to that api. And I am doing append to one model data and from there I am trying to display in my label. But when I do api calling itself and try to print the label name , Its showing crash index out of range
func showprofileapi () {
let headers = [
"cache-control": "no-cache",
"postman-token": "4c933910-0da0-b199-257b-28fb0b5a89ec"
]
let jsonObj:Dictionary<String, Any> = [
"customerID" : "5"
]
if (!JSONSerialization.isValidJSONObject(jsonObj)) {
print("is not a valid json object")
return
}
if let postData = try? JSONSerialization.data(withJSONObject: jsonObj, options: JSONSerialization.WritingOptions.prettyPrinted) {
let request = NSMutableURLRequest(url: NSURL(string: "http://MyProfile.php")! as URL,
cachePolicy: .useProtocolCachePolicy,timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
///print(error)
} else {
DispatchQueue.main.async(execute: {
if let json = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? Dictionary<String,AnyObject>
{
let status = json["status"] as? Int;
if(status == 1)
{
print("SUCCESS....")
if (json["myprofile"] as? NSDictionary) != nil
{
print("SUCCESS ......22....")
print(json)
DispatchQueue.main.async(execute: {
print("INSIDE CATEGORIES")
self.Profileddatas.append(MyProfiledData(json:json as NSDictionary))
print("Product Name : ", self.Profileddatas[0].custName)
})
}
}
}
})
}
})
dataTask.resume()
}
}
My above code is my api calling, And when I try to print the value in my console its crashing :
// print("Product Name : ", self.Profileddatas[0].custName)
My json output after api calling is :
{
"status": 1,
"message": "My Profile Details are.",
"myprofile": {
"CustomerName": "ram",
"CustomerEmail": "ram#gmail.com",
"CustomerMobile": "",
"CustomerAddress": "",
"CustomerUsername": "",
"CustomerPassword": " "
}
}
My append data model class is :
class MyProfiledData
{
var custName : String?
var custEmail : String?
var custMobile : String?
var custAddress : String?
var custUsername : String?
var custPassword : String?
init(json:NSDictionary)
{
self.custName = json["CustomerName"] as? String
self.custEmail = json["CustomerEmail"] as? String
self.custMobile = json["CustomerMobile"] as? String
self.custAddress = json["CustomerAddress"] as? String
self.custUsername = json["CustomerUsername"] as? String
self.custPassword = json["CustomerPassword"] as? String
}
}
Please help me out.
Thanks

change if (json["myprofile"] as? NSDictionary) != nil
to if let json = json["myprofile"] as? NSDictionary because your 'json' in the context of initializing MyProfiledData went wrong

You're accessing the JSON Data by it's wrong keys in Your MyProfileData Class. You have either pass the ["myprofile"] dict in the init(json) call by
if let myProfile = json["myprofile"] as? NSDictionary {
DispatchQueue.main.async(execute: {
self.Profiledatas.append(MyProfileData(json:myProfile))
})
}
or access it by their right Keys:
class MyProfiledData {
var custName : String?
var custEmail : String?
var custMobile : String?
var custAddress : String?
var custUsername : String?
var custPassword : String?
init(json:NSDictionary) {
self.custName = json["myprofile"]["CustomerName"] as? String
self.custEmail = json["myprofile"]["CustomerEmail"] as? String
self.custMobile = json["myprofile"]["CustomerMobile"] as? String
self.custAddress = json["myprofile"]["CustomerAddress"] as? String
self.custUsername = json["myprofile"]["CustomerUsername"] as? String
self.custPassword = json["myprofile"]["CustomerPassword"] as? String
}
}

In your init function it structure is not ok, it will be work if you send only my profile node of your json
{
"CustomerName": "ram",
"CustomerEmail": "ram#gmail.com",
"CustomerMobile": "",
"CustomerAddress": "",
"CustomerUsername": "",
"CustomerPassword": " "
}
use
self.Profileddatas.append(MyProfiledData(json:Json["myprofile"] as NSDictionary))

if (json["myprofile"] as? NSDictionary) != nil
{
print("SUCCESS ......22....")
print(json)
DispatchQueue.main.async(execute: {
print("INSIDE CATEGORIES")
self.Profileddatas.append(MyProfiledData(json:json["myprofile"] as! NSDictionary))
print("Product Name : ", self.Profileddatas[0].custName)
self.getvalue ()
})
}

Related

Access Value of a Same key in a dictionary of outside function

I want to access the same key of a dictionary that called name and I cant change the value of key because it is on server : here is my code :
func infoUser(complition:#escaping ([String:Any]) -> Void) {
let url = URL(string: "\(offerUrl)/api/user")! //change the url
//create the session object
let session = URLSession.shared
//now create the URLRequest object using the url object
var request = URLRequest(url: url)
request.httpMethod = "GET" //set http method as POST
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.setValue( "bearare \(profileKeychain["token"]!)", forHTTPHeaderField: "Authorization")
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard error == nil else {
return
}
guard let data = data else {
return
}
print("data is : \(data)")
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
print("this is json format: \(json)")
// handle json ...
guard let YourName = json["name"] as? String else { return }
guard let YourAddress = json["address"] as? String else { return }
guard let YourPhone = json["telephone"] as? String else { return }
guard let YourEmail = json["email"] as? String else { return }
guard let city = json["city"] as? [String: Any] else { return }
guard let title = city["title"] as? String else { return }
guard let country = json["country"] as? [String: Any] else { return }
guard let names = country["name"] as? String else { return }
let dict = ["name":YourName,"address":YourAddress,"telephone":YourPhone,"email":YourEmail,"city":city,"title":title,"country":country,"name" : names] as [String : Any]
complition(dict)
}
} catch let error {
print("error is this : \(error.localizedDescription)")
}
})
task.resume()
}
I want to access the value of names in country which its key in name like the name of user
and also this is a completion handler that I use it I called it from viewdidLoad() function :
override func viewDidLoad() {
super.viewDidLoad()
if profileKeychain["token"] != "" {
infoUser { dict in
DispatchQueue.main.async {
self.yourNamelbl.text = dict["name"] as? String
self.yourPhonelbl.text = dict["telephone"] as? String
self.yourCitylbl.text = dict["title"] as? String
self.yourMaillbl.text = dict["email"] as? String
self.yourAddresslbl.text = dict["address"] as? String
// this line
self.countryNamelbl.text = dict["name" ] as? String }}}
and in simulator the name of country and the name of user is same in labels but I dont want to happen this, what's your idea?
thanks for attention
You are overwriting the value for "name" key.
let dict = [
"name": YourName, // First write happens here
"address": YourAddress,
"telephone": YourPhone,
"email": YourEmail,
"city": city,
"title": title,
"country": country,
"name" : names // Second write, The problem is here
] as [String: Any]
UPDATE
You already have name nested inside country dictionary, so you don't need to store it one more time at the top level.
You can remove the second write from above code "name": names part and use it like following in your viewDidLoad().
let country = dict["country"] as? [String: Any]
self.countryNamelbl.text = country?["name"] as? String

Looping an array received from service

JSON from service
{
"firstname": "Utku",
"lastname": "Dalmaz",
"photos": [{
"src": "image",
"post_id": "69"
}, {
"src": "image",
"post_id": "74"
}, {
"src": "image",
"post_id": "133"
}, {
"src": "image",
"post_id": "142"
}]}
SWIFT CODE
Alamofire.request("SERVICE", method: .post, parameters: parameters).validate().responseJSON { response in
switch response.result {
case .success:
if let json = response.result.value {
var success = 0
if let dictJSON = json as? [String: AnyObject] {
if let successInteger = dictJSON["success"] as? Int {
success = successInteger
if success == 1
{
self.firstname = dictJSON["firstname"] as! String
self.lastname = dictJSON["lastname"] as! String
if let photos = dictJSON["photos"] as! Array<String> {
let postID = //post_id data
let src = //src data
let data = InboxPhotos(ID: postID!, src: src!)
self.photosArr.append(data)
}
...
I am trying to get array data from JSON service. Even though I am able to get firstname and lastname data, I cannot get and loop photos array in swift code.
How can I loop photos array and get post_id and src data into InboxPhotos and append to photosArr array?
let dictJSON = ...
guard let photos = dictJSON?["photos"] as? [[String: Any]] else { return }
let list = photos.map { InboxPhotos(ID: $0["post_id"] as! String, src: $0["src"] as! String)}
// Or more safely.
let list2: [InboxPhotos] = photos.compactMap {
guard let src = $0["src"] as? String,
let id = $0["post_id"] as? String else {
return nil
}
return InboxPhotos(ID: id, src: src)
}
I have made JSON parsing modal for your JSON Data-Type. you don't need anything just pass data at the time create a modal object and get data without hectic.
struct UserModal{
var firstname:String
var lastname:String
var photos: [PhotosModal]
init(dictData:[String: Any]) {
self.firstname = dictData["firstname"] as? String ?? ""
self.lastname = dictData["lastname"] as? String ?? ""
var photosArr = [PhotosModal]()
for data in dictData["photos"] as? [[String:Any]] ?? [] {
photosArr.append(PhotosModal(src: data["src"] as! String, post_id: data["post_id"] as! Int))
}
self.photos = photosArr
}
}
struct PhotosModal{
var src:String
var post_id:Int
init(src:String, post_id:Int) {
self.src = src
self.post_id = post_id
}
}
let userModal = UserModal(dict: dictJSON?["photos"] as? [[String: Any]])
So Make separate file for this modal file. Applying this you will follow Single responsibility class/file of SOLID principal rules.

Objects inside Array inside Object Swift

Can somebody help with parsing this kind of JSON object?
{
"array":[
{
"title":"",
"desc":""
},
{
"title":"",
"desc":""
},
{
"title":"",
"desc":""
}
]
}
My code doesnt work
let task = self.session.dataTask(with: url) {
data, response, error in
if let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
for case let announcment in json!["array"]{
guard let title = announcment["title"] as? String,
let description = announcment["desc"] as? String,
else{ return }
}
task.resume()
Thank in advance for any help!
Pretty-printing your JSON makes it easier to work through:
{
"array":[
{
"title":"",
"desc":""
},
{
"title":"",
"desc":""
},
{
"title":"",
"desc":""
}
]
}
You need to get the array first. An array of dictionaries is of type [[String: Any]].
let task = self.session.dataTask(with: url) {
data, response, error in
if let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
guard let announcements = json["array"] as? [[String: Any]]
else { return }
announcements.forEach { announcement in
guard let title = announcement["title"] as? String,
let description = announcement["desc"] as? String
else { return }
// Do something with the result
}
}
}
task.resume()
You can structure your data and make it Codable:
struct Root: Codable {
let array: [Announcement]
}
struct Announcement: Codable {
let title: String
let desc: String
}
let data = Data("""
{"array":[{"title":"","desc":""},{"title":"","desc":""},{"title":"","desc":""}]}
""".utf8)
do {
let announcements = try JSONDecoder().decode(Root.self, from: data).array
for announcement in announcements {
print(announcement)
}
} catch {
print(error)
}
This will print
Announcement(title: "", desc: "")
Announcement(title: "", desc: "")
Announcement(title: "", desc: "")

How to filter a NSArray by Key:value, that is in a NSDictionary

Im trying to figure out how to filter out the Dictionary of NSArrays by the value "name"
// Is an Array of a dictionary, by key : values
var teamFilteredList = [[String:Any]]()
var teamList = [[String:Any]]()
Fetch:
let string = "https://api/connect/"
let url = NSURL(string: string)
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "GET"
let session = URLSession.shared
let tache = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! NSArray {
print(jsonObj)
teamList = jsonObj as! [[String : Any]]
DispatchQueue.main.async {
self.teamCollectionView.reloadData()
}
}
}
tache.resume()
This code is the result and gets put in teamList
JSON:
({
id = 1;
logo = "testLogo";
name = "testTeam1";
"url" = "https://example.com";
},
{
id = 2;
logo = "testLogo";
name = "testTeam2";
"url" = "https://example.com";
},
{
id = 3;
logo = "testLogo";
name = "testTeam3";
"url" = "https://example.com";
})
Example of what it looks like once put in teamList:
let example = [[id: "1", logo: "image", name: "testTeam1", url: "https"], [id: "2", logo: "image", name: "testTeam2", url: "https"]]
Code Trying to Filter:
let array2Name = teamFilteredList.flatMap { $0["name"] }
teamFilteredList = teamList.reduce(teamFilteredList, { result, value in
!array2Name.contains(where: { $0 as! _OptionalNilComparisonType == value["testTeam3"] }) ? result + [value]: result
})
So far this code has been horrible. But there's nothing else online that tells me how to do it cut dry. So I've been stuck.
leads to crash:
Could not cast value of type '__NSCFString'
Update:
I have a collection view that is populated from a fetch by a NSURL that gives me a Dictionary filled with NSArrays and i want to filter out all the NSArray indexes in that dictionary by a value that is already in the NSArray Indexes by the key: "name"
This answered Question in this link final answer, but its not up to date and yields errors.
here
It's so, so much easier with a custom struct and JSONDecoder
Create a struct
struct Team : Decodable {
let id : Int
let logo : String
let name : String
let url : URL
}
Create the arrays
var teamList = [Team]()
var teamFilteredList = [Team]()
Decode the JSON
let string = "https://api/connect/"
let url = URL(string: string)!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error { print(error); return }
do {
self.teamList = try JSONDecoder().decode([Team].self, from: data!)
DispatchQueue.main.async {
self.teamCollectionView.reloadData()
}
} catch {
print(error)
}
}
task.resume()
And filter the array
teamFilteredList = teamList.filter{ $0.name == "testTeam3" }
Try to use this predicate
teamFilteredList.filter({ fromDict in return !array2Name.contains(where: { $0 == fromDict["name"] as? String ?? ""})})
The trick is that Swift isn't expressive in its errors. It says that don't use where, why? because the compiler really expects a String, because your closure is not correct.
And if the array2Name is a dictionary also. Try to change the where clause to:
where: { ($0["name"] as? String ?? "<<Empty1>>") == (fromDict["name"] as? String ?? "<<Empty2>>") }
So the whole function would be:
teamFilteredList.filter({ fromDict in return !array2Name.contains(where: { ($0["name"] as? String ?? "<<Empty1>>") == (fromDict["name"] as? String ?? "<<Empty2>>") })})
If you want to learn more effective functional programming and you don't mind some JavaScript, try this
Learn Effective Functional Programming in JavaScript)

Parse JSON with an Optional in swift

Optional({"session":{"_id":"574fe96fa28f9aaadb000034","application_id":41262,"created_at":"2016-06-02T08:08:15Z","device_id":0,"nonce":21576,"token":"5b04f409c06ecf24ad2d9479a1ef7ef78916f864","ts":1464854895,"updated_at":"2016-06-02T08:08:15Z","user_id":0,"id":7274}})
I need to parse and save token from the above dictionary (in Swift)
My request goes like this :
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let dict = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(dict)")
}
task.resume()
Need to parse dict
JSON parsing/mapping can be a pain and time consuming.
I just happen to have made a tool for it :
Jenerator
Download from here and move to /usr/local/bin/
It is a little command line tool written in Swift to generate a Swift model based on a JSON. If I passed it your JSON it gave me back this :
import Foundation
struct SOSession {
var created_at : String
var _id : String
var id : Int
var device_id : Int
var token : String
var updated_at : String
var nonce : Int
var user_id : Int
var ts : Int
var application_id : Int
init(data:[String:AnyObject]) {
self.created_at = (data["created_at"] as? String) ?? ""
self._id = (data["_id"] as? String) ?? ""
self.id = (data["id"] as? Int) ?? 0
self.device_id = (data["device_id"] as? Int) ?? 0
self.token = (data["token"] as? String) ?? ""
self.updated_at = (data["updated_at"] as? String) ?? ""
self.nonce = (data["nonce"] as? Int) ?? 0
self.user_id = (data["user_id"] as? Int) ?? 0
self.ts = (data["ts"] as? Int) ?? 0
self.application_id = (data["application_id"] as? Int) ?? 0
}
static func fromSource(urlString : String) -> SOSession? {
guard let url = NSURL(string: urlString), data = NSData(contentsOfURL: url) else {
return nil
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)
if let outerDict = json as? [String:AnyObject], let dict = outerDict["session"] as? [String:AnyObject] {
return SOSession(data: dict)
}
} catch {}
return nil
}
}
Getting the Token then becomes as simple as this :
let myToken = SOSession.fromSource("someUrl")?.token
To use Jenerator I saved your JSON in a file on my desktop and ran in terminal :
jenerator "$HOME/Desktop/so-1.json" StackOverflowQuestion1 SO
jenerator "path-to-file-with-json" save-file-name class-prefix
You can now copy the generator code to your project.
In Swift 4:
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let data = responseJSON as? [String: Any] {
if let success = data["success"] as? Int {
if success == 1 {
self.dataArray = data["results"] as! Array
label.text = self.dataArray[row]["id"] as? String
// parse in similar fashion
}
}
}
}

Resources