Swift - Why is my JSON object element only adding the last array element? - swift

I have a problem with my JSON object. Everything is working fine creating and printing out my JSON object, apart from the idQty part. It only prints the last key value result. I assume I have a problem with my for loop. If anybody can point out where I've went wrong, it would be of huge help.
Code below:
struct Order: Codable {
let idQty: [IdQty]
let collection: String
let name: String
let phone: Int
let doorNum: Int
let street: String
let postcode: String
}
struct IdQty: Codable {
let itemId: Int
let qty: Int
}
class CheckoutServer: NSObject, URLSessionDataDelegate {
var inputVals = [Int:Int]()
var idQty = [IdQty]()
var collection = String()
var name = String()
var phone = Int()
var doorNum = Int()
var street = String()
var postcode = String()
var request = URLRequest(url: NSURL(string: "http://192.168.1.100/api/AddOrder.php")! as URL)
func downloadItems() {
for(key,value) in inputVals {
idQty = [IdQty(itemId: key,qty: value)]
}
let order = Order(idQty: idQty,collection: collection,name: name,phone: phone,doorNum: doorNum,street: street,postcode: postcode)
let encodedOrder = try? JSONEncoder().encode(order)
var json: Any?
request.httpMethod = "POST"
if let data = encodedOrder {
json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
if let json = json {
}
}
let postParameters = "json="+String(describing: json!)
request.httpBody = postParameters.data(using: .utf8)
print(String(describing: json!))
let defaultSession = URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: request) { (data, response, error) in
if error != nil {
print("Failed to upload data at Menu Type Items")
} else {
print("Data uploaded")
}
}
task.resume()
}
}
Below is the output. the 'idQty' part only ever returns the last entry in the [Int:Int] dictionary:
{
collection = Delivery;
doorNum = 4;
idQty = (
{
itemId = 14;
qty = 2;
}
);
name = James;
phone = 4355345;
postcode = Test;
street = TestStreet;
}

You should append new value to your array instead of recreating it on each iteration
for(key,value) in inputVals
{
idQty.append(IdQty(itemId: key,qty: value))
}

Related

How To Remove and Add Double Nested Elements in Firestore Array

I have a nested Codable Object In another object array in another object. I don't see how I can use FieldValue.arrayRemove[element]. Anyone know to do this? Thanks. I am trying to make it so that I can remove a cardField element in the LevelCard element in the job array.
Here is my code
struct Job: Identifiable, Codable {
var id: String? = UUID().uuidString
var uid: String = ""
var title: String = ""
var description: String = ""
var images: [ImagesForJob] = []
var levelCards: [LevelCard] = []
var tags: [Tag] = []}
struct LevelCard: Identifiable, Codable {
var id = UUID().uuidString
var name: String = ""
var color: String = "A7D0FF"
var fields: [CardField] = []}
struct CardField: Identifiable, Codable {
var id = UUID().uuidString
var name: String = ""
var value: String = ""
var type: FieldType = .Text}
func removeExistingCard(id: String, card: LevelCard) {
var data: [String: Any] = ["":""]
do {
let encoder = JSONEncoder()
let jsonData = try! encoder.encode(card)
data = try JSONSerialization.jsonObject(with: jsonData, options: []) as! [String : Any]
} catch {
print("Error encoding account info\(error.localizedDescription)")
}
db
.collection("listings")
.document(id)
.updateData(["levelCards": FieldValue.arrayRemove([data])]) {err in
if let err = err {
withAnimation {
self.errMsg = "Failed to delete card: \(err.localizedDescription)"
self.showErrMsg = true
}
return
}
self.getUsrLstngs()
}
}
func removeExistingField(id: String, field: CardField) {
var data: [String: Any] = ["":""]
do {
let encoder = JSONEncoder()
let jsonData = try! encoder.encode(field)
data = try JSONSerialization.jsonObject(with: jsonData, options: []) as! [String : Any]
} catch {
print("Error encoding account info\(error.localizedDescription)")
}
db
.collection("listings")
.document(id)
.updateData(["levelCards": FieldValue.arrayRemove([data])]) {err in
if let err = err {
withAnimation {
self.errMsg = "Failed to delete card: \(err.localizedDescription)"
self.showErrMsg = true
}
return
}
self.getUsrLstngs()
}
}
Also, Bonus, Does anyone know how to ignore the "id" variable when encoding all of my objects to Firestore? Thanks again.

Save complex relational data in CoreData

I'm back on a learning course in SwiftUI using CoreData. I have three entities:
User // Has many Customers
Customer // Belongs to User and has many PartExchanges
PartExchange // Belongs to customer
When user first installs the app after they logged in, I fetch some initial data to be saved (the above: customers, part exchnages etc...):
struct AuthResponse: Decodable {
let error: String?
let token: String?
let userData: UserObject?
let customers: [Customers]?
struct UserObject: Decodable {
let FirstName: String?
let Surname: String?
let EmailAddress: String?
let UserID: String
}
struct Customers: Decodable {
let FirstName: String?
let Surname: String?
let EmailAddress: String?
let Customer_ID: String
let PartExchanges: [PartExchangeData]?
}
}
// In another file and not inside AuthResponse
struct PartExchangeData: Decodable {
let Registration: String?
let Customer_ID: String?
let PartExchange_ID: String?
let Variant: String?
let Colour: String?
}
AuthResponse is only used when user first logs in or reinstalls the app to get the initial data from our API:
// The exact data I have
import SwiftUI
class AuthController {
var emailUsername: String = ""
var password: String = ""
func login() -> Void {
guard let url = URL(string: "http://localhost:4000/api/auth") else {
print("Invalid URL")
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body: [String: AnyHashable] = [
"emailUsername": emailUsername,
"password": password
]
request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .fragmentsAllowed)
// Make the request
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
if let decodedResponse = try?
decoder.decode(AuthResponse.self, from: data) {
DispatchQueue.main.async {
if decodedResponse.error != nil {
// Tell user?
return
}
let userObject = UserModel()
userObject.createUser(authObject: decodedResponse)
}
return
}
}
print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
}.resume()
}
}
Last, the UserModel:
class UserModel: ObservableObject {
private let fetchRequest: NSFetchRequest<User> = User.fetchRequest()
private let viewContext = PersistenceController.shared.container.viewContext
#Published var saved: Bool = false
var firstName: String = ""
var surname: String = ""
var emailAddress: String = ""
var token: String = ""
var userId: String = ""
init() {...}
public func createUser(authObject: AuthResponse) -> Void {
do {
// Create a user on first login
let user = User(context: viewContext)
let customer = Customer(context: viewContext)
let partExchange = PartExchange(context: viewContext)
//let userCustomers: [AuthResponse.Customers]
user.firstName = authObject.userData!.FirstName
user.surname = authObject.userData!.Surname
user.emailAddress = authObject.userData!.EmailAddress
user.token = authObject.token!
user.userId = authObject.userData!.UserID
// Save customers
for cus in authObject.customers! {
customer.firstName = cus.FirstName
customer.surname = cus.Surname
user.addToCustomers(customer)
// save part exchanges
for px in cus.PartExchanges! {
partExchange.registration = px.Registration
partExchange.partExchangeId = px.PartExchange_ID
partExchange.variant = px.Variant
customer.addToPartExchanges(partExchange)
}
}
try viewContext.save()
saved = true
print("ALL SAVED!!")
} catch {
let error = error as NSError
// If any issues, rollback? viewContext.rollback()
fatalError("Could not save user: \(error)")
}
}
public func logOut() {
// Only remove the token....
}
}
The issue I'm having with this approach is when saving; it's saving the last customer in the loop.
Xcode generated some extensions for User, Customer and PartExchnage and inside User, I see a function: #NSManaged public func addToCustomers(_ values: NSSet):
[..]
user.addToCustomers(<what-goes-here>)
My User entity saves correctly. Customer only has the last data from the api array. How to correctly save the user with many customers, where the each customer has many part exchanges?
You need to create a new object for each iteration in each of your loops since each object created will be stored as a separate item in Core Data
So change createUser like this
public func createUser(authObject: AuthResponse) -> Void {
do {
let user = User(context: viewContext)
user.firstName = authObject.userData!.FirstName
// more properties ...
for cus in authObject.customers! {
let customer = Customer(context: viewContext)
customer.firstName = cus.FirstName
customer.surname = cus.Surname
user.addToCustomers(customer)
for px in cus.PartExchanges! {
let partExchange = PartExchange(context: viewContext)
partExchange.registration = px.Registration
partExchange.partExchangeId = px.PartExchange_ID
partExchange.variant = px.Variant
customer.addToPartExchanges(partExchange)
}
}
try viewContext.save()
saved = true
print("ALL SAVED!!")
} catch let error = error as NSError {
//Either log the error and return some status or throw it
//FatalError is a bit to much in this situation
fatalError("Could not save user: \(error)")
}
}

Add Data Sorting in TableView with Exception | Swift

Essentially I currently have the following JSON Parse logic in place to group and present the JSON Array in a tableview.
Currently in the fetchJSON function I am grouping person and sorting alphabetically. How can I add logic that makes an exception to this sort and allows person = Jack, to always be on top of the sort and the rest stay alphabetical.
Is there a way to keep the person = "Jack" at the top of the tableview no matter the other tableview data?
Below is my current code:
private func fetchJSON() {
guard let url = URL(string: "\(BaseURL.url)test.php"),
let value = variable.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)
else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "test=\(value)".data(using: .utf8)
URLSession.shared.dataTask(with: request) { data, _, error in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let res = try decoder.decode([Portfolio].self, from: data)
let grouped = Dictionary(grouping: res, by: { $0.person })
let keys = grouped.keys.sorted()
self.sections = keys.map({Section(name: $0, items: grouped[$0]!)})
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
catch {
print(error)
}
}.resume()
}
Structure:
struct Section {
let name : String
var items : [Portfolio]
}
struct Portfolio: Decodable {
let person: String
let serial: String
var checkbox: Int
var isSelected : Bool {
get { return checkbox == 1 }
set { checkbox = newValue ? 1 : 0 }
}
enum CodingKeys : String, CodingKey {
case person, serial, checkbox
}
}
I think you can do that in multiple ways to your own custom sort. But for coding simplicity, you can consider this alternative solution. After sorting, remove, and insert the item again.
var keys = grouped.keys.sorted()
if let index = keys.firstIndex(of: "jack") {
let jack = keys.remove(at: index)
keys.insert(jack, at: 0)
}

how to use random string to let or var to url link

how to use random string to let or var to url link
i want to make random string for url
let url = URL(string:"https://www.pallive.net/random.json")
or see the code when i change values in the site linke in the app do not changed,but if i chnage name of url it change
the code not reload if i change the value in json and keep same file
if i want to reload i have to change the name of file how to do some thange
auotmatic change the url and keep the orginal in the ftp server
import Foundation
class Episode
{
var title: String?
var description: String?
var thumbnailURL: URL?
var url: URL?
var episodes = [Episode]()
init(title: String, description: String, thumbnailURL: URL, createdAt: String, author: String)
{
self.title = title
self.description = description
self.thumbnailURL = thumbnailURL
}
init(espDictionary: [String : AnyObject])
{
self.title = espDictionary["title"] as? String
// description = espDictionary["description"] as? String
thumbnailURL = URL(string: espDictionary["thumbnailURL"] as! String)
self.url = URL(string: espDictionary["link"] as! String)
}
static func downloadAllEpisodes(completion: #escaping ([Episode]) -> ()) {
var episodes = [Episode]()
let url = URL(string:"https://www.pallive.net/random.json")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error)
completion(episodes)
}
else {
if let jsonData = data ,let jsonDictionary = NetworkService.parseJSONFromData(jsonData) {
let espDictionaries = jsonDictionary["episodes"] as! [[String : AnyObject]]
for espDictionary in espDictionaries {
let newEpisode = Episode(espDictionary: espDictionary)
episodes.append(newEpisode)
}
}
completion(episodes)
DispatchQueue.main.async(execute: {
completion(episodes)
})
}
}.resume()
}
func randomString(_ length: Int) -> String {
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let len = UInt32(letters.length)
var randomString = ""
for _ in 0 ..< length {
let rand = arc4random_uniform(len)
var nextChar = letters.character(at: Int(rand))
randomString += NSString(characters: &nextChar, length: 1) as String
}
return randomString
}
}

Type [SubscriptType] does not conform to protocol StringLiteralConvertible error

Type [SubscriptType] does not conform to protocol StringLiteralConvertible
// JsonRequest.swift
class JsonRequest {
var title: String?
var postBody: String?
var coverImage: String?
init(json: NSDictionary){
self.title = json["title"] as? String
self.postBody = json["body"] as? String
self.coverImage = json["img_url"] as? String
}
}
// ViewController.swift file
var posts = [JsonRequest]()
let feedUrl = NSURL(string: "http://example.com/json")
// 2
if let JSONData = NSData(contentsOfURL: feedUrl!) {
// 3
var jsonResult = NSJSONSerialization.JSONObjectWithData(JSONData, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
var myJSON = JSON(jsonResult)
let arrayLength = myJSON["dump"].array?.count
if arrayLength != 0 {
for postIndex in 0...arrayLength! - 1 {
var postArray = myJSON["dump"][postIndex]["title"] as? [NSDictionary]
for item in postArray {
posts.append(JsonRequest(json: item))
}
}
}
}
I want to append from my JSON["dump"][0, 1, 2]["title"] to postArray array, save all this titles in the this array, but here is the this error. How can I fix it and save my titles in this Array?
You can not cast postArray as [NSDictionary] because it is not NSDictionary.
But It is string and here is example code for you.
var posts = [String]()
let feedUrl = NSURL(string: "http://example.com/en/feed")
// 2
if let JSONData = NSData(contentsOfURL: feedUrl!) {
// 3
var jsonResult = NSJSONSerialization.JSONObjectWithData(JSONData, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
var myJSON = JSON(data:JSONData)
let arrayLength = myJSON["dump"].array?.count
if arrayLength != 0 {
for postIndex in 0...arrayLength! - 1 {
var post = myJSON["dump"][postIndex]["title"].stringValue
posts.append(post)
println(posts)
}
}
}
EDIT
Update your code this way:
JsonRequest.swift
class JsonRequest {
var title: String?
var postBody: String?
var coverImage: String?
init(json: JSON){
self.title = json["title"].stringValue
self.postBody = json["body"].stringValue
self.coverImage = json["img_url"].stringValue
}
}
ViewController.swift
var posts = [JsonRequest]()
let feedUrl = NSURL(string: "http://example.com/en/feed")
// 2
if let JSONData = NSData(contentsOfURL: feedUrl!) {
// 3
var jsonResult = NSJSONSerialization.JSONObjectWithData(JSONData, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
var myJSON = JSON(data:JSONData)
let arrayLength = myJSON["dump"].array?.count
var dict = myJSON["dump"]
if arrayLength != 0 {
for postIndex in 0...arrayLength! - 1 {
var tempDict = dict[postIndex]
posts.append(JsonRequest(json: tempDict))
}
}
}
Hope it helps.