Creating JSON Array in Swift to update MySQL database - arrays

I hope this isn't a stupid question, I have been trawling the solutions and haven't been able to work this out..
In my main view controller I get data from a MySQL database using PHP and JSON. The user then selected relevant items from a table view by clicking on a custom button in a custom cell. I am at the point where I can add to/remove from the list based on which buttons are clicked/unclicked...
private var selectedItems = [Int: String]()
func cellButtonTapped(cell: CustomCell) {
let indexPath = self.tableView.indexPathForRowAtPoint(cell.center)!
let selectedItem = postsCollection[indexPath.row]
let item = selectedItem.product
let id = selectedItem.Id
let idItem : [Int:String] = [id:"\(item)"]
if selectedItems[id] == nil {
// now val is not nil and the Optional has been unwrapped, so use it
selectedItems[id] = "\(item)" //item
} else {
selectedItems[id] = nil
}
println("\(selectedItems)")
}
If I select items on the list it is displayed like this as I select the items. When I deselect them, the get removed from the list.
[6: Mybulen, 7: Ecotrin XL, 5: Aspen Simvastatin, 8: Lorien]
I would like to create a JSON Array and POST the array to a PHP file that I have the updates the database.. The resultant JSON Array should look something like this...
[{"Id":"6","repeatflag":"1"},{"Id":"7","repeatflag":"1"},{"Id":"5","repeatflag":"1"}]
So basically, any item I select gets added to the array with a "repeatflag" set to "1". My PHP file has a script that updates the "repeatflag" in the MySQL database. When the user is ready, they will click on a send button that will POST their selection in the the JSON Array. Hope that makes sense?
Thanks.

Well the code from you looks a little bit weird to me, maybe its because I don't know its context... But you can build an JSONArray you want like this:
class ViewController: UIViewController, UITableViewDelegate {
var jsonArrayWithItemsToSendToPHP: [[String: AnyObject]] = [[String: AnyObject]]()
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedItem = postsCollection[indexPath.row]
var jsonObjectToPutToArray: [String: AnyObject] = [String: AnyObject]()
jsonObjectToPutToArray["id"] = selectedItem.Id
jsonObjectToPutToArray["name"] = selectedItem.product
jsonObjectToPutToArray["repeatflag"] = 1
jsonArrayWithItemsToSendToPHP.append(jsonObjectToPutToArray)
}
}

class ViewController: UIViewController, UITableViewDelegate {
var jsonArrayWithItemsToSendToPHP: [[String: AnyObject]] = [[String: AnyObject]]()
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedItem = postsCollection[indexPath.row]
var jsonObjectToPutToArray: [String: AnyObject] = [String: AnyObject]()
jsonObjectToPutToArray["id"] = selectedItem.Id
jsonObjectToPutToArray["name"] = selectedItem.product
jsonObjectToPutToArray["repeatflag"] = 1
jsonArrayWithItemsToSendToPHP.append(jsonObjectToPutToArray)
}
}

Related

swift auto refresh Cell

which I add or remove from another ViewController
Im display this array.count in tableView
How in swift I can auto updates cell for array.count?
without Timer and Pull to refresh
Or how can I make refresh when loadedCart.count haw change?
Thanks
class TestTABLEVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableViewT: UITableView!
var CellT = TestTableViewCell()
var def = UserDefaults.standard
var loadedCart = [[String:Any]]()
override func viewDidLoad() {
super.viewDidLoad()
tableViewT.estimatedRowHeight = 100
tableViewT.dataSource = self
tableViewT.delegate = self
loadedCart = UserDefaults.standard.array(forKey: "cartt") as? [[String: Any]] ?? []
//Here need add auto update
}
cell for row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TestTableViewCell
let item = loadedCart[indexPath.row]
cell.nameLbl?.text = item["name"] as? String
cell.priceLbl.text = item["price"] as? String
cell.qntLbl.text = item["qty"] as? String
let im = item["image"] as? NSData
cell.PhoroUmage.image = UIImage(data: im! as Data)
return cell
}
Btn, when click - remove arr and reload cells
#IBAction func Btn(_ sender: UIButton) {
def.removeObject(forKey: "cartt")
print("remove is OK")
//Here need add auto update when btn pressed
}
If I understand you correctly, you can use reactive programming for this. For example Bond framework can be used like this:
let todoItems: SafeSignal<[TodoItem]> = ....
let tableView: UITableView = ...
class TodoItemCell: UITableView Cell { ... }
...
todoItems.bind(to: tableView, cellType: TodoItemCell.self) { (cell, item) in
cell.titleLabel.text = item.name
}
Using this framework, your table view will automatically reload when there are any changes to the source array. You will find more about usage on table views at this link.
you probably need to use notifications. i.e. send a notification when something new gets added to your cart.
Then set up an observer and, every time the observer notices a change, update the tableview with reload data.
A similar use case is listed here I think but would need to be adapted for your needs (if you need more help someone more expert than me will be able to help probably with the specifics!) Automatically Reload TableViewController On Rewind
Add
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let carts = UserDefaults.standard.array(forKey: "cartt") as? [[String: Any]] {
loadedCart = carts
}
DispatchQueue.main.async{
self.tableViewT.reloadData()
}
}

How to add json data to array or similar using Swift

I am fairly new to Swift and I am having a few issues with getting understanding how to do what I want to do.
I am currently testing some stuff with json.
What I am trying to do is to append the data I get from my json data into an array. And when my array contains the data I wish to present it to my UICollectionView. I am assuming that I should be using an array.
import UIKit
import Foundation
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getData() {
let path = "http://myurl/test.json"
let url = URL(string: path)
let session = URLSession.shared
let task = session.dataTask(with: url!) { (data: Data?, response: URLResponse?, error: Error?) in
let json = JSON(data: data!)
for result in json["dokumentstatus"]["dokutskott"]["utskott"].array! {
let punkter = result["punkt"].string!
print("punkt: \(punkt)")
let rubrik = result["rubrik"].string
print("rubrik: \(rubrik)")
let forslag = result["forslag"].string
print("förslag: \(forslag)")
}
}
task.resume()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return //someArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CustomCollectionViewCell
cell.customLabel.text = //Put the data form rubrik variable
cell.customTW.text = //Put the data from foreleg variable
return cell
}
}
the function getData() gets the correct json data I just need help understanding how to put this data to an array.
(Also, I know I probably shouldn't be getting the data in the ViewController, but this is only a test.)
import Foundation
class Information: NSObject {
var punkter: String?
var rubrik: String?
var forslag: String?
}
I'm thinking that maybe I should be using an array that looks something like this:var someArray = [Information]()
But I do not know how to then use my getData()
Or maybe I should be using three different arrays, one for each of my json variables.
Since you're still using a custom class (well done!, three different arrays are horrible) it's correct to declare a data source array like you suggested
var someArray = [Information]()
Most likely a struct is sufficient, I recommend to use non-optional strings
struct Information {
var punkter : String
var rubrik : String
var forslag : String
}
If the properties won't change you could even use let to make the properties constants.
To populate the array use the nil coalescing operator to check for nil,create the Information instance with the memberwise initializer and append the instance to the datasource array. Then reload the collection view on the main thread.
...
for result in json["dokumentstatus"]["dokutskott"]["utskott"].array! {
let punkter = result["punkt"].string ?? ""
let rubrik = result["rubrik"].string ?? ""
let forslag = result["forslag"].string ?? ""
let information = Information(punkter:punkter, rubrik:rubrik, forslag:forslag)
self.someArray.append(information)
}
DispatchQueue.main.async {
self.collectionView.reloadData()
}
...
Edit:
To display the data in cellForItemAtIndexPath use
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CustomCollectionViewCell
let information = someArray[indexPath.row]
cell.customLabel.text = information.rubrik
cell.customTW.text = information.foreleg
return cell
}

Getting objects from Parse into an Core Data via an Array

I have a tableview that gets it's data from Parse via a queryForTable function. This works fine. I would like to get the same objects from Parse and add them to an array that I can later store in Core Data! Does anyone know how to do this? I have added my code below to show how I add it to a TableView.
Thanks for the help in advance. ;)
//MARK: Query for Table with the details
override func queryForTable() -> PFQuery {
let discoveryQuery = PFQuery(className: "DiscoveryDetails")
discoveryQuery.cachePolicy = .NetworkElseCache
discoveryQuery.whereKey("discoveryID", equalTo: PFObject(withoutDataWithClassName: "Discovery", objectId: "\(varInDDT!.objectId!)"))
discoveryQuery.orderByDescending("createdAt")
return discoveryQuery
}
....
//I strangely cannot find the type to declare that will hold all the
values that are shown in cellForRowAtIndexPath. PFObject does not seem
to work either. Maybe there is something I am missing about the
objects type that's universal to all.
var objectsArray : [String] = []
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? {
//Discovery Items TableViewCell
var discoveryDetailItemsCell:DiscoveryDetailTableViewCell! = tableView.dequeueReusableCellWithIdentifier("DiscoveryDetailTableViewCell") as? DiscoveryDetailTableViewCell
if (discoveryDetailItemsCell == nil) {
tableView.registerNib(UINib(nibName: "DiscoveryDetailTableViewCell", bundle: nil), forCellReuseIdentifier:"DiscoveryDetailTableViewCell")
discoveryDetailItemsCell = tableView.dequeueReusableCellWithIdentifier("DiscoveryDetailTableViewCell") as? DiscoveryDetailTableViewCell
}
//Background Colour of the Cell
discoveryDetailItemsCell.titleLabel.text = object?.objectForKey("exerciseName") as? String
discoveryDetailItemsCell.titleLabel.textColor = UIColor.whiteColor()
discoveryDetailItemsCell.durationAndSetsLabel.text = "\((object?.objectForKey("durationOrSets"))!)"
discoveryDetailItemsCell.minAndSetLabel.text = "mins"
discoveryDetailItemsCell.distanceAndRepsLabel.text = "\((object?.objectForKey("distanceOrReps"))!)"
discoveryDetailItemsCell.kmAndRepsLabel.text = "km"
discoveryDetailItemsCell.weightLabel.text = "\((object?.objectForKey("weight"))!)"
discoveryDetailItemsCell.kgsLabel.text = ""
discoveryDetailItemsCell.dot1.textColor = UIColor.grayColor()
discoveryDetailItemsCell.dot2.textColor = UIColor.grayColor()
//Load Images
let backgroundImage = object?.objectForKey("workoutImage") as? PFFile
discoveryDetailItemsCell.backgroundImageView.layer.masksToBounds = true
discoveryDetailItemsCell.backgroundImageView.layer.cornerRadius = 8.0
discoveryDetailItemsCell.backgroundImageView.image = UIImage(named: "loadingImage")
discoveryDetailItemsCell.backgroundImageView.file = backgroundImage
discoveryDetailItemsCell.backgroundImageView.loadInBackground()
//My Attempt at adding one of the values into an array
objectsArray = [(object?.objectForKey("exerciseName"))! as! String]
return discoveryDetailItemsCell
}

JSON Array won't display in UITable swift

Im trying to create a table which fills in its data from an online JSON file. I currently have the JSON file online and being called into the class and getting converted into an array, however when I try set my text as this array data nothing displays.
cell.textLabel?.text = "\(locationName[indexPath.row])"
However if I set the data in the array it works however I need the data to be from the JSON file.
var array: double = ["1", "2", "3"]
Here is my table class code with the array code. Any help would be great thanks
class SpotsDataClass: UITableViewController {
var locationName = [String]()
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(.GET, "http://woamph.com/savedLocations.json")
.response { request, response, data, error in
if let data = data {
let json = JSON(data: data)
for locationLoop in json {
let usersJSON = locationLoop.1["user"].stringValue
self.locationName.append(usersJSON)
//let longitudeJSON = locationLoop.1["longitude"].doubleValue
//self.array2.append(longitudeJSON)
}
for i in 0 ..< self.locationName.count {
print("\(self.locationName[i])")
//print("\(self.array2[i])")
//self.locationNameLabel.text = "Location Name: \(self.array1[i])"
}
//self.titleLabel.text = "Spots Near You"
//self.locationNameLabel.text = "Location Name: \(spotData.locationName)"
//self.ratingLabel.text = "Rating: \(spotData.rating)"
//self.userLabel.text = "Posted By: \(spotData.user)"
//
}
}
}
//Mark: - UITableDataSource
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return locationName.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("spotTable", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel?.text = "\(locationName[indexPath.row])"
return cell
}
}
The Alamofire request executes asynchronously. You need to explicitly tell your table view to reload when the network request is done, otherwise you're populating your array from the results but the table view has already been loaded by the time your remote data has been loaded.
So, after
for locationLoop in json {
let usersJSON = locationLoop.1["user"].stringValue
self.locationName.append(usersJSON)
}
Add:
tableView.reloadData()

Passing value selected cell to another ViewController

I have two ViewControllers. For the first ViewController, it displays my Array data on the table. I want to get the indexPath of the selected cell, and pass this data to another ViewController.
In my First ViewController
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
var nameList = [NameManager]()
#IBOutlet weak var NameTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
NameTable.dataSource = self
GetData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func GetData(){
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: "http://www.json-generator.com/api/json/get/bPfifKWNaq?indent=2")!)
request.HTTPMethod = "GET"
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let data = data{
do{
let resultJSON = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions())
let resultArray = resultJSON as? NSArray
for jsonObjectString in resultArray!{
let code = jsonObjectString["code"] as! String
let name = jsonObjectString["name"] as! String
let description = jsonObjectString["description"] as! String
self.nameList.append(NameManager(code: code, name: name, description: description))
}
self.nameList.count
dispatch_async(dispatch_get_main_queue(), {
self.NameTable.reloadData()
})
}catch _{
print("Received not-well-formatted JSON")
}
}
if let response = response {
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
let count = nameList.count
return count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let myCell = NameTable.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as UITableViewCell
myCell.textLabel?.text = nameList[indexPath.row].name
myCell.detailTextLabel?.text = nameList[indexPath.row].description
return myCell
}
In my Second ViewController, which is also another class, I want to capture the indexPath of what was selected. Using the index value, I search my Array and pass that particular object to the next class. I don't have codes for this as I don't know how it works.
You could create a property outside the scope of your class and then set that within the cellForRowAtIndexPath method. That property could be accessed in your second view controller. You’ll want to look at the tableview method didSelectRowAtIndexPath as that will be where you set your property to the cell that’s been selected.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
appDelegate().index = indexPath.row
}
I’ve made a super simple project on github showing two ways of creating a property outside the scope of your view controller. One way is creating a variable within AppDelegate to be accessed via a singleton, the other is a Globals.swift file.
Hope this helps!
If you want to pass values to the controller which pops after tapping on the cell, using a singleton wouldn't be an elegant way. If you are using storyboards, then you have to use 'prepare for segue'. You implement the method in the class that handles the transfer and set all the properties in another view controller.
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "SecondVC") {
// set properties
}
}

Resources