Why is this data not displaying in my Swift 3 table - ios

So I'm trying to parse some JSON data retrieved from a server and display it nicely in a table, ive followed the suggestions here: UITableView example for Swift and managed to get the example working.
However with the data im parsing the table remains blank.
Can anyone see where im going wrong?
import UIKit
import SwiftyJSON
class LogsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let animals: [String] = ["Horse", "Cow", "Camel", "Sheep", "Goat"]
var arrayCount:Int = 0
struct Item {
let name : String
let lockTime : String
let type : String
}
// cell reuse id (cells that scroll out of view can be reused)
let cellReuseIdentifier = "cell"
var items = [Item]()
#IBOutlet weak var textUodate: UIStackView!
override func viewDidLoad() {
super.viewDidLoad()
// Register the table view cell class and its reuse id
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier)
tableView.delegate = self
tableView.dataSource = self
// Do any additional setup after loading the view.
let lockid = UserDefaults.standard.value(forKey: "LockID")!
// let email = UserDefaults.standard.value(forKey: "email")!
//get the data from the server for that specific lock id
let u = UserDefaults.standard.value(forKey: "userIP")!
var request = URLRequest(url: URL(string: "http://\(u):3000/logs")!)
request.httpMethod = "POST"
let postString = "LockID=\(lockid)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
print(response ?? " ")
}
let responseString = String(data: data, encoding: .utf8)
if let data = responseString?.data(using: String.Encoding.utf8) {
let resString = JSON(data: data)
if resString["success"].stringValue == "true"
{
self.arrayCount = (resString["message"].count)
print(self.arrayCount)
let returnedArray = resString["message"].arrayValue
for item in returnedArray {
let name = String(describing: item["name"])
let lockTime = String(describing: item["lockTime"])
let type = String(describing: item["type"])
self.items.append(Item(name:name, lockTime:lockTime, type:type))
}
}
else if resString["success"].stringValue == "false"
{
print(resString["success"].stringValue)
}
}
}
task.resume()
DispatchQueue.main.async{
self.tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayCount
}
// create a cell for each table view row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!
let item = items[indexPath.row]
let cellText = "\(item.name) \(item.type) At: \(item.lockTime) "
cell.textLabel?.text = cellText
print(cellText)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You tapped cell number \(indexPath.row).")
}

Data is not displaying because you didn't reload the table view after you append the items array. Please reload the table view at the end of task closure
let task = URLSession.shared.dataTask(with: request) { data, response, error in
// ......
// ......
self.tableView.reloadData()
}

Related

Converting Image Data into Base64 String For MySQL Blob and Decoding it Back

I'm trying to send data (first name, last name, age, image) to a MySQL database. And I can. The following is what I have.
class PostViewController: UIViewController {
#IBAction func selectTapped(_ sender: UIButton) {
postData()
}
func postData() {
var request = URLRequest(url: URL(string: "http://www.mywebsite.tv/post.php")!)
request.httpMethod = "POST"
let fName = firstField.text!
let lName = lastField.text!
let ageStr = ageField.text!
let image = imageView.image!
guard let pictStr = convertImageBase64(image: image) else {
return
}
let postString = "a=\(fName)&b=\(lName)&c=\(ageStr)&d=\(pictStr)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("error=\(String(describing: error))")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(String(describing: response))")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(String(describing: responseString))")
}
task.resume()
}
func convertImageBase64(image: UIImage) -> String? {
guard let pictData = UIImagePNGRepresentation(image) else {
return nil
}
let strBase64: String = pictData.base64EncodedString(options: Data.Base64EncodingOptions.lineLength64Characters)
return strBase64
}
}
And populating UITableView with data from MySQL..
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, DataModelProtocol {
// MARK: - Variables
var myItems = NSArray()
// MARK: - IBOutlets
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// somehow loading data //
}
// MARK: - TableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ProfileTableViewCell
let item: PictureModel = myItems[indexPath.row] as! PictureModel
cell.firstLabel.text = item.fName
cell.lastLabel.text = item.lName
cell.ageLabel.text = item.ageStr
print(item.pictStr!) // returning iVBORw0KGgoAAAANSUh...
if let img = convertBase64Image(base64String: item.pictStr!) {
cell.pictureImageView.image = img
}
return cell
}
func convertBase64Image(base64String: String) -> UIImage? {
if let pictData = Data(base64Encoded: base64String, options: Data.Base64DecodingOptions.ignoreUnknownCharacters) {
return UIImage(data: pictData)
} else {
return nil
}
}
}
The thing is cell.pictureImageView.image is always nil. And I now know why. When I post a picture, a sample base64 string is
iVBORw0KGgoAAAANSUhEUgAAAFYAAACACAYAAACRMZ7FAAAAAXNSR0IArs4c6QAA\r\nABxp...
And the decoded string that I get is
iVBORw0KGgoAAAANSUhEUgAAAFYAAACACAYAAACRMZ7FAAAAAXNSR0IArs4c6QAA ABxp...
So the Data.Base64DecodingOptions.ignoreUnknownCharacters option actually replaces \r\n with a white space. How can I encode an image and then decode it back the same?
Drop the .lineLength64Characters options:
func convertImageBase64(image: UIImage) -> String? {
guard let pictData = UIImagePNGRepresentation(image) else {
return nil
}
let strBase64: String = pictData.base64EncodedString(options: [])
return strBase64
}
That way the string will not have a \r\n in it in the first place.

Swift 3: Custom Cell not displaying data

Im receiving a JSON array from php and trying to passing data to table view. However, my tableview does not display the data.
class test1ViewController: UIViewController , UITableViewDataSource, UITableViewDelegate {
var TableData:Array< String > = Array < String >()
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return TableData.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! testTableViewCell
cell.mylabel1.text = TableData[indexPath.row]
return cell
}
func get_data_from_url(_ link:String)
{
let url:URL = URL(string: link)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "GET"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return
}
print(data!)
self.extract_json(data!)
})
task.resume()
}
func extract_json(_ data: Data)
{
let json: Any?
do
{
json = try JSONSerialization.jsonObject(with: data, options: [])
// print(json!)
}
catch
{
return
}
guard let data_list = json as? NSArray else
{
return
}
if let countries_list = json as? NSArray
{
for i in 0 ..< data_list.count
{
if let country_obj = countries_list[i] as? NSDictionary
{
if let name = country_obj["name"] as? String
{
if let age = country_obj["age"] as? String
{
TableData.append(name + age)
}
}
}
}
}
}
When the array gives initial values like
animals = ["hinno", "ali", "khalil"],
the values appear to custom cell, but when i take the data from a server and do the json conversion, nothing appears.
tableview.reloadData() any time you make changes to the array.
If reload Data of the collection or tableView doesn't work use that in Dispatch code like this
DispatchQueue.main.async {
yourTableViewName.reloadData()
}

pass json id from one table view controller into another table view controller in swift 3

I already new in swift 3 and objetive c, right now I am stuck into how can I pass the id of each row to another table view controller when the user tap in the row the user want to go.
Here is the json data firstFile:
[
{"id_categoria":"1","totalRows":"323","nombre_categoria":"Cirug\u00eda"},
{"id_categoria":"2","totalRows":"312","nombre_categoria":"Med Interna"},
{"id_categoria":"3","totalRows":"6","nombre_categoria":"Anatomia"},
{"id_categoria":"4","totalRows":"24","nombre_categoria":"Anestesiologia"},
...]
Here is my first table view controller:
import UIKit
class CatMedVC: UIViewController, UITableViewDataSource {
#IBAction func volver(_ sender: Any) { }
#IBOutlet weak var listaCategoria: UITableView!
var fetchedCategoria = [Categoria]()
override func viewDidLoad() {
super.viewDidLoad()
listaCategoria.dataSource = self
parseData()
}
override var prefersStatusBarHidden: Bool{
return true
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedCategoria.count
}
public func tableView(_ tableView: UITableView, cellForRowAt IndexPath: IndexPath) ->
UITableViewCell {
let cell = listaCategoria.dequeueReusableCell(withIdentifier: "cell")
cell?.textLabel?.text = fetchedCategoria[IndexPath.row].esp
cell?.detailTextLabel?.text = fetchedCategoria [IndexPath.row].totalRows
return cell!
}
func parseData() {
let url = "http://www.url.com/firstFile.php" //in json format
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = "GET"
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request) { (data, response, error) in
if(error != nil) {
print("Error")
}
else {
do {
let fetchedData = try JSONSerialization.jsonObject(with:data!, options: .mutableLeaves) as! NSArray
//print(fetchedData)
for eachFetchedCategoria in fetchedData {
let eachCategoria = eachFetchedCategoria as! [String : Any]
let nombre_categoria = eachCategoria["nombre_categoria"] as! String
let totalRows = eachCategoria["totalRows"] as! String
let id_categoria = eachCategoria["id_categoria"] as! String
self.fetchedCategoria.append(Categoria(nombre_categoria: nombre_categoria, totalRows: totalRows, id_categoria: id_categoria))
}
//print(self.fetchedCategoria)
self.listaCategoria.reloadData()
}
catch {
print("Error 2")
}
}
}
task.resume()
}
}
class Categoria {
var nombre_categoria : String
var totalRows : String
var id_categoria : String
init(nombre_categoria : String, totalRows : String, id_categoria : String) {
self.nombre_categoria = nombre_categoria
self.totalRows = totalRows
self.id_categoria = id_categoria
}
}
So I need pass the id_categoria String into the another table view to show the data for the id selected previously...here I don't know how to do it...I have the json file waiting for the id selected previously..but I don't know how to catch it into the url
Here the second table view:
import UIKit
class EspMedVC: UITableViewController {
var TableData:Array< String > = Array < String >()
var EspecialidadArray = [String]()
#IBAction func volver(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
get_data_from_url("http://www.url.com/secondFile.php?id=") // Here I need to put the id_categoria String in json format
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
cell.textLabel?.text = TableData[indexPath.row]
return cell
}
func get_data_from_url(_ link:String)
{
let url:URL = URL(string: link)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "GET"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return
}
self.extract_json(data!)
})
task.resume()
}
func extract_json(_ data: Data)
{
let json: Any?
do
{
json = try JSONSerialization.jsonObject(with: data, options: [])
}
catch
{
return
}
guard let data_list = json as? NSArray else
{
return
}
if let nombre_especialidad = json as? NSArray
{
for i in 0 ..< data_list.count
{
if let nombre_esp_obj = nombre_especialidad[i] as? NSDictionary
{
if let nombre_especialidad = nombre_esp_obj["subesp"] as? String
{
if let totalRows = nombre_esp_obj["totalRows"] as? String
{
TableData.append(nombre_especialidad + " [" + totalRows + "]")
}
}
}
}
}
DispatchQueue.main.async(execute: {self.do_table_refresh()})
}
func do_table_refresh()
{
self.tableView.reloadData()
}
}
This is a rough guide, please search for the methods in the documentation or here at other questions inside stackoverflow.
1) Add a variable inside your EspMedVC that will hold the "id_categoria String" that should be displayed.
2) Add a variable inside your CatMedVC that will hold the "id_categoria String" that the user selected.
3) Implement the "didSelectRow" delegate method from your tableview inside the "CatMedVC", inside this method you should set the variable set on step 2.
4) Implement the "prepareForSegue" method inside your CatMedVC, inside the the implementation you should retrieve the destination VC, cast it to "EspMedVC" and set the variable from step 1.
5) On the "viewDidLoad" from EspMedVC you can now use the variable set on step 2 to query your JSON and update the table view accordingly.

Connecting JSON from external server to Swift tableView

I am new to Swift, and am trying to create a table that reads JSON data from my website. I followed some tutorials, and was able to get my code to work with a table controller. Now I'm trying to use a view controller with a table view inside, so I can have more customization. My problem is, I can't get the data to actually show up when I try to use my new code.
This is what I have in my viewController.swift:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var TableData:Array< String > = Array < String >()
override func viewDidLoad() {
super.viewDidLoad()
get_data_from_url("http://www.stevenbunting.org/Alliris/service.php")
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = TableData[indexPath.row]
return cell
}
func get_data_from_url(_ link:String)
{
let url:URL = URL(string: link)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "GET"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return
}
self.extract_json(data!)
})
task.resume()
}
func extract_json(_ data: Data)
{
let json: Any?
do
{
json = try JSONSerialization.jsonObject(with: data, options: [])
}
catch
{
return
}
guard let data_list = json as? NSArray else
{
return
}
if let countries_list = json as? NSArray
{
for i in 0 ..< data_list.count
{
if let country_obj = countries_list[i] as? NSDictionary
{
if let country_name = country_obj["user"] as? String
{
if let country_code = country_obj["friendlist"] as? String
{
TableData.append(country_name + " [" + country_code + "]")
}
}
}
}
}
DispatchQueue.main.async(execute: {self.do_table_refresh()
})
}
func do_table_refresh()
{
self.tableView.reloadData()
}
}
Probably you didn't set the tableView's dataSource. To do this, implement the UITableViewDataSource-protocol in the ViewController-class and set the tableView's dataSource-property to self in the viewDidLoad(), for example:
class ViewController: UIViewController, UITableViewDataSource {
// ...
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
// ...
}
//...
}
Oh, and don't forget about the Apple Transport Security-settings, otherwise you won't see anything as iOS doesn't allow HTTP anymore, you have use HTTPS. The right way to handle this is to get an SSL-Certificate for your domain.
The quick'n'dirty and absolutely not recommended way is to disable ATS or to set an exception for certain, trustworthy domains.

UITable Won't display. Value type 'FilmsAPITableViewCell' has no member 'movieTitle'

I am getting build errors when trying to display jSON data in Xcode using Swift 3. I am going to copy a portion of my code to this page with hopes you guys can assist me.
I have found similar questions on this site however answers don't seem to help.
class FilmsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
weak var tableView : UITableView!
var FilmArray = [String]()
let film_url = "https://www.testing.com/api/resources/films/1"
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for:indexPath) as! FilmsAPITableViewCell
// Adding the right informations
cell.movieTitle.text = FilmArray[indexPath.row]
// Returning the cell
return cell
}
// #IBOutlet weak var FilmsView: UITableView!
// weak var tableView : UITableView!
// var FilmArray = [String]()
//
// let film_url = "https://www.distribber.com/api/resources/films/1"
//
override func viewDidLoad() {
super.viewDidLoad()
let tableView = UITableView (frame:view.bounds)
view.addSubview(tableView)
self.tableView = tableView
tableView.dataSource = self
tableView.delegate = self
// func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// return 1
// }
// func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// // Getting the right element
// //let films = FilmArray[indexPath.row]
//
//
// // Instantiate a cell
// //let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "moviecell")
// let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! FilmsAPITableViewCell
// // cell.movieTitle.text = FilmArray[indexPath.row]
// // Adding the right informations
// cell.movieTitle.text = FilmArray[indexPath.row]
// // Returning the cell
// return cell
// }
// }
//}
let url:URL = URL(string: film_url)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "GET"
request.setValue("740c94c51891c02b64d6c78840b478fe0b02fe2c", forHTTPHeaderField: "X-API-KEY")
request.setValue("Basic YmhlZW0uZW5nckBnbWFpbC5jb206YmgzM20=", forHTTPHeaderField: "Authorization")
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let paramString = ""
// for (key, value) in post_data
// {
// paramString = paramString + (key as! String) + "=" + (value as! String) + "&"
// }
//
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return
}
let json: Any?
do
{
json = try JSONSerialization.jsonObject(with: data!, options: [])
// Prasing JSON
var parsedData = try JSONSerialization.jsonObject(with: data!, options: []) as! [String:Any]
print(parsedData)
if let FilmArray = parsedData["films"] as? NSArray {
for movieTitle in FilmArray{
if let filmDict = movieTitle as? NSDictionary{
if let film = filmDict.value(forKey: "title") {
self.FilmArray.append(film as! String)
}
OperationQueue.main.addOperation({
self.tableView.reloadData()
})
}
}
}
print("Hello")
self.tableView.reloadData()
print(self.FilmArray)
}
catch
{
return
}
guard let server_response = json as? NSDictionary else
{
return
}
if let data_block = server_response["data"] as? NSDictionary
{
if let session_data = data_block["session"] as? String
{
// self.login_session = session_data
let preferences = UserDefaults.standard
preferences.set(session_data, forKey: "session")
// DispatchQueue.main.async(execute: self.LoginDone)
}
}
})
task.resume()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is also output from FilmsAPITableViewCell.swift
import UIKit
import UIKit
class FilmsAPITableViewCell: UITableViewCell {
#IBOutlet weak var movieTitle: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
The reason why movieTitle is nil is because your custom cell class does not have that label outlet. You need to create a UILabel in your .xib (or storyboard) and create an outlet connection inside your custom cell class.
It also seems like no self.tableView.reloadData() exists in your completion block. Try adding that right after the print("Hello") line.
P.S. Don't forget to dispatch the reload to the main queue.
Here is also your code which I edited as to get it working:
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
let url:URL = URL(string: film_url)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "GET"
request.setValue("740c94c51891c02b64d6c78840b478fe0b02fe2c", forHTTPHeaderField: "X-API-KEY")
request.setValue("Basic YmhlZW0uZW5nckBnbWFpbC5jb206YmgzM20=", forHTTPHeaderField: "Authorization")
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let paramString = ""
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return
}
var json:Any?
do
{
if let existingData = data {
json = try JSONSerialization.jsonObject(with: existingData, options: [])
}
// Prasing JSON
if let parsedData = json as? [[String:Any]] {
for dict in parsedData {
if let title = dict["title"] as? String {
self.FilmArray.append(title)
}
}
OperationQueue.main.addOperation({
self.tableView.reloadData()
})
}
}
catch
{
return
}
guard let server_response = json as? NSDictionary else
{
return
}
if let data_block = server_response["data"] as? NSDictionary
{
if let session_data = data_block["session"] as? String
{
// self.login_session = session_data
let preferences = UserDefaults.standard
preferences.set(session_data, forKey: "session")
// DispatchQueue.main.async(execute: self.LoginDone)
}
}
})
task.resume()
}

Resources