How can i add specific JSON value to another array in Swift? - arrays

I'm new in IOS programming.
I have a json array described with code below.
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as?
NSDictionary
print("json: \(String(describing: json))")
Output of code is;
json: Optional({
vendors = (
{
firm = "XXX firm";
id = 1;
"show_firm" = 1;
},
{
firm = "ZZZZZ firm";
id = 2;
"show_firm" = 1;
}
);
})
I want to add only firm values to another array like firms = ["XXX firm" , "ZZZZZ firm"]
How can I do that?
Any help would be greatly appreciated.
#witek bobrowski asked String(data: data!, encoding: .utf8) output.This output is below also. By the way json data comes from server as http post response.
json2: Optional("{\"vendors\":[{\"id\":\"1\",\"firm\":\"XXX firm\",\"show_firm\":\"1\"},{\"id\":\"2\",\"firm\":\"ZZZZZ firm\",\"show_firm\":\"1\"}]}")

I believe the best way to go is to decode the JSON and then add the firms value to an array.
struct model: Decodable{
var vendors: [decodingModel]
}
struct decodingModel: Decodable{
var firm: String
var id: Int
var show_firm: Int
}
let decoder = JSONDecoder()
do{
let result = try decoder.decode(model.self, from: jsonData)
let firmsArray = result.vendors.compactMap({$0.firm})
}catch{
print(error)
}
Since you have not posted your son structure, I can only assume you have a Json where vendor is an array of jsons. firmsArray is what you are looking for.
If this doesn't work is probably because of the wrong model and decodingModel. If you post your json structure, I will update the code so that you can properly decode your json

the best way is to create Decodable Model for your json as below:
struct Firm: Decodable {
let id: Int
let name: String
let showFirm: Int
enum CodingKeys: String, CodingKey {
case id
case name = "firm"
case showFirm = "show_firm"
}
}
I created this factory method to simulate your json response locally based on what you provided in the question
struct FirmFactory {
static func makeFirms() -> [Firm]? {
let json = [
[
"firm": "XXX firm",
"id": 1,
"show_firm": 1,
],
[
"firm": "ZZZZZ firm",
"id": 2,
"show_firm": 1,
],
]
// you should use the following code to decode and parse your real json response
do {
let data = try JSONSerialization.data(
withJSONObject: json,
options: .prettyPrinted
)
return try JSONDecoder().decode([Firm].self, from: data)
} catch {
print("error \(error.localizedDescription)")
return nil
}
}
}
now you will be able to map only the firm names as you request you can test like this
let firmNames = FirmFactory.makeFirms()?.map { $0.name }
print("firmNames \(firmNames)")

I answered my own question again. There are 2 answers given but i didn't use any of these in my code. May be these two answers are usable but because of i'm new in IOS i couldn't use any of them. At the end of long google search i solved my problem as below.
let vendors = json!["vendors"]! as! [[String : AnyObject]]
for firm in vendors {
let firm1 = firm["firm"]! as! String
self.providerArray.append(firm1)
}
I hope this answer solves someone else's problem like me.

Related

Convert JSON to Array Xcode

I am trying to implement two side by side UIPickerViews, one for Type and the other for Subtype. Each is an array of strings
var typePickerData: [String] = [String]()
var subtypePickerData: [String] = [String]()
Each is a pretty simple array of names:
typePickerData = ["Monitor","Keyboard","Mouse"]
When the viewDidLoad fires or when a new Type is selected, the app makes a remote db call and I get a response containing JSON of subtype names which I want to use to populate and reload the subtype picker.
I am stuck on converting the response into subtypePickerData
let decoder = JSONDecoder()
if let jsonResponse = try? decoder.decode([String].self, from: data) {
print("parse subtype response \(jsonResponse)")
subtypePickerData = jsonResponse
DispatchQueue.main.async {
self.subtypePicker.reloadAllComponents()
}
}
What am I doing wrong here converting the JSON response to subtypePickerData?
this is what I am getting from the remote call
result Optional(<__NSArrayM 0x281370e70>( { name = Monitor; },{ name = "AV Accessories"; },{ name = Computer; },{ name = "Monitor Stands"; },{ name = "Bracket/Mount"; },{ name = Screen; }
Here is my updated code after solving issue
let decoder = JSONDecoder()
if let jsonResponse = try? decoder.decode(Subtypes.self, from: data) {
SubtypeList = jsonResponse.result
self.subtypePickerData = SubtypeList.map{$0.Name}
DispatchQueue.main.async {
self.subtypePicker.reloadAllComponents()
}
}
Yor response seems to be not type of [String] but an array of custom objects. You first need to create a struct to decode your response data to.
struct NameContainer{
var name: String
}
then do:
//change decoding to String array to decoding array of custom object NameContainer
if let jsonResponse = try? decoder.decode([NameContainer].self, from: data) {
print("parse subtype response \(jsonResponse)")
subtypePickerData = jsonResponse.map{$0.name} // Map your objects to strings and assign them
DispatchQueue.main.async {
self.subtypePicker.reloadAllComponents()
}
}
Remarks:
Never use try? this will obfuscate all errors. Use a proper do/catch block, handle the error or mark your function throws and handle the error up the chain.
DispatchQueue.main.async {
self.subtypePicker.reloadAllComponents()
Bracket/Mount"; },{ name = Screen; } –

Problem converting JSON to Array with Swift

I try to convert a JSON to an Array but I face some issue and do not know how to sort it out.
I use Swift 5 and Xcode 12.2.
Here is the JSON from my PHP query:
[
{
Crewcode = AAA;
Phone = 5553216789;
Firstname = Philip;
Lastname = MILLER;
email = "pmiller#xxx.com";
},
{
Crewcode = BBB;
Phone = 5557861243;
Firstname = Andrew;
Lastname = DEAN;
email = "adean#xxx.com";
}
]
And here is my Swift code :
let url: URL = URL(string: "https://xxx.php")!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
}
else {
print("Data downloaded")
do {
if let jsondata = (try? JSONSerialization.jsonObject(with: data!, options: [])) {
print(jsondata)
struct Crew: Decodable {
var Code: String
var Phone: String
var Firstname: String
var Lastname: String
var email: String
}
let decoder = JSONDecoder()
do {
let people = try decoder.decode([Crew].self, from: jsondata as! Data)
print(people)
}
catch {
print(error)
}
}
}
}
}
task.resume()
When I run my code I get the following error:
Could not cast value of type '__NSArrayI' (0x7fff86b930b0) to 'NSData' (0x7fff86b911e8).
2020-12-09 14:52:48.988468+0100 FTL[57659:3019805] Could not cast value of type '__NSArrayI' (0x7fff86b930b0) to 'NSData' (0x7fff86b911e8).
Could not cast value of type '__NSArrayI' (0x7fff86b930b0) to 'NSData' (0x7fff86b911e8).
Should you have any idea to get it right, I thank you in advance for your assistance on this !
You are deserializing the JSON twice by mixing up JSONSerialization and JSONDecoder.
Delete the first one
if let jsondata = (try? JSONSerialization.jsonObject(with: data!, options: [])) {
– By the way the JSON in the question is neither fish nor fowl, neither JSON nor an NS.. collection type dump –
and replace
let people = try decoder.decode([Crew].self, from: jsondata as! Data)
with
let people = try decoder.decode([Crew].self, from: data!)
and the struct member names must match the keys otherwise you have to add CodingKeys

Issue getting count of records in JSON array using Alamofire | Swift 5

Essentially I have the following function:
func stagedCount() {
let url = "example.com"
let parameters: Parameters =
["person": "\(name)"]
Alamofire.request(url, method: .post, parameters: parameters).responseData(completionHandler : { response in
if let allObjects = response.result.value as? NSArray{
print("Array length is \(allObjects.count)")
}
}
)}
The JSON response from the URL looks like this:
[
{
"person": "Jake",
"hobby": "soccer"
},
{
"person": "Mary",
"hobby": "surfing"
}
]
I am getting the following response and no count is currently printing.
Cast from 'Data?' to unrelated type 'NSArray' always fails
How can I fix this to get a count of the amount of records in the array? The result I am looking for is 2
The error is pretty clear. responseData will return a JSON String data. You can not convert Data to an Array. What you need is to decode your json data into an array of person structures:
struct Person {
let person: String
let hobby: String
}
when decoding the response:
guard
let data = response.data,
let json = String(data: data, encoding: .utf8)
else { return }
print("json:", json)
do {
let people = try JSONDecoder().decode([Person].self, from: data)
print(people.count)
for person in people {
print(person)
}
} catch {
print(error)
}

How can I create an array of URLs with SwiftyJSON and Alamofire? [duplicate]

This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 6 years ago.
I have the following problem I need to retrieve an array of URL's from a JSON Object in order to download all the pictures of the products from an e-commerce site in my app.
The JSON I get looks like this:
[
{
........
........
.........
........
"images": [
{
"id": 976,
"date_created": "2016-08-10T15:16:49",
"date_modified": "2016-08-10T15:16:49",
"src": "https://i2.wp.com/pixan.wpengine.com/wp-content/uploads/2016/07/canasta-familia.jpg?fit=600%2C600&ssl=1",
"name": "canasta-familia",
"alt": "",
"position": 0
}
],
.......
.......
.......
So far I've been able to get only one string from the array doing this.
Alamofire.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers)
.responseJSON { response in
if let jsonValue = response.result.value {
let jsonObject = JSON(jsonValue)
var jsonArray = jsonObject[0]["images"][0]["src"].stringValue
print(jsonArray)
}
}
which gives me this
https://xx.xx.xx/xxxx.xxxxx.xxxx/xx-xxxxx/uploads/2016/07/canasta-familia.jpg?fit=600%2C600&ssl=1
But what I need is to access all the elements inside "images" & "src" not just the first element of the index of both.
How can I do this?
Any ideas?
Step 1:
Create a custom object to represent the pictures. We'll call this "Picture".
struct Picture {
let id:Int
let date_created:String
let date_modified:String
let src:String
let name:String
let alt:String
let position:Int
}
Step 2:
Create an array to hold all of your product pictures. Make sure you pay attention to the scope in which you create it. It should ideally outside of your download function.
var productPictures = [Picture]()
Step 3:
Download your JSON file, make a Picture struct for each image, and add each Picture to your productPictures array.
Alamofire.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers)
.responseJSON { response in
switch response.result {
case .success:
self.productPictures.removeAll()
guard let json = response.result.value as? [String:Any] else {
print("couldn't retrieve json as a dictionary")
return
}
guard let images = json["images"] as? [AnyObject] else {
print("there was a problem accessing the images key")
return
}
for image in images {
guard let id = image["id"] as? Int,
let date_created = image["date_created"] as? String,
let date_modified = image["date_modified"] as? String,
let src = image["src"] as? String,
let name = image["name"] as? String,
let alt = image["alt"] as? String,
let position = image["position"] as? Int
else {
print("There was a problem accessing one of the picture variables, or it was missing")
continue
}
let newPicture = Picture(id: id,
date_created: date_created,
date_modified: date_modified,
src: src,
name: name,
alt: alt,
position: position)
self.productPictures.append(newPicture)
}
case .failure(let error):
print("could not download and retrieve product images. An error occurred: \(error)")
return
}
}
Now you have an array full of Picture structs, each containing all of the necessary information pulled from your JSON download.
Note
This doesn't use SwiftyJSON, but it should work and give you the same intended result. I hope this helps!
The following lines of code should work as I've tested myself with an actual dataset.
import Alamofire
import SwiftyJSON
Alamofire.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers)
.responseJSON { response in
if let jsonValue = response.result.value {
let jsonObject = JSON(jsonValue)
if let array = jsonObject.array {
for i in 0..<array.count {
if let images = array[i]["images"].array {
for i in 0..<images.count {
let src = images[i]["src"]
print(src) // save src in an array or whatever
}
}
}
}
}

How we can find an element from [AnyObject] type array in swift

I have [AnyObject] array
var updatedPos = [AnyObject]()
I am setting data in that according to my requirement like!
let para:NSMutableDictionary = NSMutableDictionary()
para.setValue(posId, forKey: "id")
para.setValue(posName, forKey: "job")
let jsonData = try! NSJSONSerialization.dataWithJSONObject(para, options: NSJSONWritingOptions())
let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding) as! String
self.updatedPos.append(jsonString)
Now in my code i have some requirement to remove the object from this array where id getting matched according to requirement Here is the code which i am trying to implement
for var i = 0; i < updatedPos.count; i++
{
let posItem = updatedPos[i]
print("Id=\(posItem)")
let pId = posItem["id"] as? String
print("secRId=\(pId)")
if removeId! == pId!
{
updatedPos.removeAtIndex(i)
}
}
Here print("Id=\(posItem)") give me output asId={"id":"51","job":"Programmer"} but here i am not able to access id from this object. here print("secRId=\(pId)") give me nil
First of all use native Swift collection types.
Second of all use types as specific as possible.
For example your [AnyObject] array can be also declared as an array of dictionaries [[String:AnyObject]]
var updatedPos = [[String:AnyObject]]()
Now create the dictionaries and add them to the array (in your example the dictionary is actually [String:String] but I keep the AnyObject values).
let para1 : [String:AnyObject] = ["id" : "51", "job" : "Programmer"]
let para2 : [String:AnyObject] = ["id" : "12", "job" : "Designer"]
updatedPos.append(para1)
updatedPos.append(para2)
If you want to remove an item by id use the filter function
let removeId = "12"
updatedPos = updatedPos.filter { $0["id"] as? String != removeId }
or alternatively
if let indexToDelete = updatedPos.indexOf{ $0["id"] as? String == removeId} {
updatedPos.removeAtIndex(indexToDelete)
}
The JSON serialization is not needed for the code you provided.
PS: Never write valueForKey: and setValue:forKey: unless you know exactly what it's doing.
After some little bit stuffs I have found the very easy and best solution for my question. And I want to do special thanks to #vadian. Because he teach me new thing here. Hey Thank you very much #vadian
Finally the answer is I had covert posItem in json Format for finding the id from Id={"id":"51","job":"Programmer"} this string
And the way is
let data = posItem.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
if let dict = json as? [String: AnyObject] {
let id = dict["id"]
if removeId! == id! as! String
{
updatedLoc.removeAtIndex(i)
}
}
}
catch {
print(error)
}

Resources