Show data from JSON in UITableView - mysql

....................................................................................................................................................................
I get the data and print it. Maybe the code is not correct I'm just new into swift, but I don't have any errors in Xcode. There's something missing but I just don't know what.
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
struct Class: Codable {
let first_name: String
let last_name: String
let email: String
enum CodingKeys: String, CodingKey {
case first_name = "first_name"
case last_name = "last_name"
case email = "email"
}
}
#IBOutlet weak var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://x.de/x.php")
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
guard let data = data, error == nil else { print(error!); return }
let decoder = JSONDecoder()
let classes = try! decoder.decode([Class].self, from: data)
for myClass in classes {
print(myClass.first_name)
print(myClass.last_name)
print(myClass.email)
}
}
).resume()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableview.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//return myarray.count
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "groupCell", for: indexPath) as UITableViewCell
return cell
}
}

Several issues
Your view controller is missing dataSource, an Array that holds list of users
Update the array (dataSource) once remote data is received
Reload UITableView once the array (dataSource) changes, using tableView.reloadData()
Within numberOfRowsInSection return the number of array elements dataSource.count
UITableView.dequeueReusableCell(withIdentifier:for:) requires that you register a cell class or xib using tableview.register method
Lastly, instead of underscores, as first_name, use camelCase variable naming convention, as firstName
struct User: Codable {
let firstName: String
let lastName: String
let email: String
enum CodingKeys: String, CodingKey {
case firstName = "first_name"
case lastName = "last_name"
case email = "email"
}
}
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableview: UITableView!
private var dataSource = [User]() {
didSet {
self.tableview.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableview.register(UITableViewCell.self, forCellReuseIdentifier: "groupCell")
self.tableview.dataSource = self
self.tableview.delegate = self
let url = URL(string: "https://example.com/users.php")
URLSession.shared.dataTask(with: url!, completionHandler: { [weak self] (data, response, error) in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "An error occurred")
return
}
// Within `dataTask` we are on background thread, we must update our UITableView on main thread
DispatchQueue.main.async {
self?.dataSource = try! JSONDecoder().decode([User].self, from: data)
}
}).resume()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableview.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "groupCell", for: indexPath)
let user = self.dataSource[indexPath.row]
cell.textLabel?.text = user.firstName
return cell
}
}
Above code yields

In the cellForRowAt func you have to do something like that :
cell.textLabel?.text = myarray[indexPath.row]
because the text of myarray should be displayed at a label or whatever

Related

Type 'HeroStruct.Type' cannot conform to 'Decodable', how can i solve that?

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var hero = [HeroStruct]()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
navigationController?.navigationBar.barTintColor = UIColor.systemYellow
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.systemYellow ]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: nil)
cell.textLabel?.text = ""
cell.backgroundColor = .systemYellow
return cell
}
func getJsonData(completion: #escaping () -> () ) {
let url = URL(string: "https://api.opendota.com/api/heroStats")
let task = URLSession.shared.dataTask(with: url!) { data, response, error in
if error != nil {
print(error?.localizedDescription)
}else {
do {
let result = try JSONDecoder().decode(HeroStruct.Type, from: data!)
}catch {
print(error)
}
}
}
}
}
import Foundation
struct HeroStruct : Decodable {
let localized_name : String
let primary_attr : String
let attack_type : String
let legs : Int
let img : String
}
First code block is my ViewController.swift page,
second code block is my HeroStruct.swift page,
I tried to get data from Json but i got error like this:
Type 'HeroStruct.Type' cannot conform to 'Decodable'
How can i solve this?
let result = try JSONDecoder().decode([HeroStruct].Type, from: data!)`
I tried write like this but doesn't work. Need help ,thanks.
Replace [HeroStruct].Type with [HeroStruct].self. Whenever you want to decode something, always use .self & not .Type.

JSON Parsing swift, Always catch statement executing

I have UITableViewController, i'm trying to parse data from url,
Always catch statement executing, that prints "something" in the console.
in Storyboard i added reuse identifier to the table view cell.
'''
class TableViewController: UITableViewController {
final let url = URL(string: "http://jsonplaceholder.typicode.com/posts")
private var posts = [Post]()
override func viewDidLoad() {
super.viewDidLoad()
downloadJson()
}
func downloadJson() {
guard let downloadURL = url else { return }
URLSession.shared.dataTask(with: downloadURL) { (data, response, error) in
guard let data = data, error == nil, response != nil else {
return
}
do {
let decoder = JSONDecoder()
let tempPosts = try decoder.decode(Posts.self, from: data)
print(tempPosts)
self.posts = tempPosts.posts
DispatchQueue.main.async {
self.tableView.reloadData()
}
} catch {
print("something")
}
}.resume()
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = posts[indexPath.row].title
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
'''
'''
class Posts: Codable {
let posts: [Post]
init(posts: [Post]) {
self.posts = posts
}
}
class Post: Codable {
let userId: Int
let id: Int
let title: String
let body: String
init(userId: Int, id: Int, title: String, body: String) {
self.userId = userId
self.id = id
self.title = title
self.body = body
}
}
'''
If the Post model is,
struct Post: Codable {
let userId, id: Int
let title, body: String
}
Use [Posts].self instead of Posts.self while parsing the data.
let tempPosts = try decoder.decode([Post].self, from: data)

Search UITableView cells using UISearchBar text

I want to show filtered cells in UITableView using UISearchBar, but it's not working. My search function is at the end of my code.
import UIKit
struct User2: Codable {
let firstName: String
let lastName: String
let email: String
let userid: String
enum CodingKeys: String, CodingKey {
case firstName = "first_name"
case lastName = "last_name"
case email = "email"
case userid = "user_id"
}
}
class SearchViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableview: UITableView!
#IBOutlet var searchBtn: UISearchBar!
private var dataSource = [User]() {
didSet {
self.tableview.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableview.register(UITableViewCell.self, forCellReuseIdentifier: "groupCell")
self.tableview.dataSource = self
self.tableview.delegate = self
let url = URL(string: "https://ex.com/ex.php")
URLSession.shared.dataTask(with: url!, completionHandler: { [weak self] (data, response, error) in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "An error occurred")
return
}
DispatchQueue.main.async {
self?.dataSource = try! JSONDecoder().decode([User].self, from: data)
}
}).resume()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableview.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "groupCell", for: indexPath)
let user = self.dataSource[indexPath.row]
cell.textLabel?.text = user.firstName + " " + user.lastName
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let user = self.dataSource[indexPath.row]
let userVC = DataViewController(user: user)
self.navigationController?.pushViewController(userVC, animated: true)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
User2 = User2.filter({ (item) -> Bool in
let heading: NSString = ((item["firstName"]! as? String)! + (item["lastName"]! as! String)) as NSString
return (heading.range(of: searchText, options: NSString.CompareOptions.caseInsensitive).location) != NSNotFound
})
self.tableview.reloadData()
}
}
A better approach would be to have 2 dataSources, one for normal state, another when there is active search, like so:
class SearchViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
private var dataSource = [User]() {
didSet {
self.tableview.reloadData()
}
}
private var searchDataSource: [User]? {
didSet {
self.tableView.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
...
self.searchBtn.delegate = self
}
// some changes to UITableView DataSource/Delegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.searchDataSource?.count ?? self.dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
let user = self.searchDataSource?[indexPath.row] ?? self.dataSource[indexPath.row]
...
}
}
Finally use following extension extending UISearchBarDelegate
extension SearchViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.isEmpty {
self.searchDataSource = nil
} else {
self.searchDataSource = self.dataSource.filter({
let fullName = $0.firstName + " " + $0.lastName
return fullName.range(of: searchText, options: [.anchored, .caseInsensitive]) != nil
})
}
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
if self.searchDataSource != nil && searchBar.text?.isEmpty ?? true {
self.searchDataSource = nil
}
}
}
that yields
I think filter should be applied on dataSource as, where dataSource is of kind [User2]:
let filteredArr: [User] = dataSource.filter({ $0.firstName.lowercased().contains(searchText.lowercased()) || $0.lastName.lowercased().contains(searchText.lowercased()) })
You can try to apply filtering in your dataSource like:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
let filteredArray = dataSource.filter({ user in
let username = "\(user.firstName) \(user.lastName)"
return username.range(of: searchText, options: .caseInsensitive) != nil
})
self.tableview.reloadData()
}

Swift 4 saving data from json to an array to show it in TableView

I'm trying to save the data from func getCoinData to an array sympolsCoin and array sympolsCoin to use it in my TableView
I create this class in the same ViewController.swift file :
struct Coin: Decodable {
let symbol : String
let price_usd : String }
And this in my View controller class :
var coins = [Coin]()
var sympolsCoin = [String]()
var priceUSDcoin = [String]()
func getCoinData(completion: #escaping () -> ()) {
let jsonURL = "https://api.coinmarketcap.com/v1/ticker/"
let url = URL(string: jsonURL)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
do {
self.coins = try JSONDecoder().decode([Coin].self, from: data!)
for info in self.coins {
self.sympolsCoin.append(info.symbol)
self.priceUSDcoin.append(info.price_usd)
print("\(self.sympolsCoin) : \(self.priceUSDcoin)")
completion()
}
}
catch {
print("Error is : \n\(error)")
}
}.resume()
}
And when i use the array in my TableView i got blank table !
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BitcoinTableViewCell", for: indexPath) as! BitcoinTableViewCell
cell.coinNameLable.text = sympolsCoin[indexPath.row]
cell.priceLable.text = priceUSDcoin[indexPath.row]
return cell
}
Since you are using JSONDecoder the entire logic to create and populate sympolsCoin and priceUSDcoin is pointless and redundant.
struct Coin: Decodable {
private enum CodingKeys: String, CodingKey {
case symbol, priceUSD = "price_usd"
}
let symbol : String
let priceUSD : String
}
var coins = [Coin]()
The completion handler is redundant, too. Just reload the table view on the main thread after receiving the data:
func getCoinData() {
let jsonURL = "https://api.coinmarketcap.com/v1/ticker/"
let url = URL(string: jsonURL)
URLSession.shared.dataTask(with: url!) { [unowned self] (data, response, error) in
guard let data = data else { return }
do {
self.coins = try JSONDecoder().decode([Coin].self, from: data)
DispatchQueue.main.async {
self.tableView.reloadData()
}
} catch {
print("Error is : \n\(error)")
}
}.resume()
}
In viewDidLoad load the data
override func viewDidLoad() {
super.viewDidLoad()
getCoinData()
}
In cellForRow update the UI
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BitcoinTableViewCell", for: indexPath) as! BitcoinTableViewCell
let coin = coins[indexPath.row]
cell.coinNameLable.text = coin.symbol
cell.priceLable.text = coin.priceUSD
return cell
}
Create an Outlet of tableView in ViewController Class and give it name "tableView" then
Try this code: Swift 4
func getCoinData() {
let jsonURL = "https://api.coinmarketcap.com/v1/ticker/"
let url = URL(string: jsonURL)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
do {
self.coins = try JSONDecoder().decode([Coin].self, from: data!)
for info in self.coins {
self.sympolsCoin.append(info.symbol)
self.priceUSDcoin.append(info.price_usd)
print("\(self.sympolsCoin) : \(self.priceUSDcoin)")
self.tableView.reloadData()
}
}
catch {
print("Error is : \n\(error)")
}
}.resume()
}
Call this function in ViewDidLoad like this
override func viewDidLoad() {
super.viewDidLoad()
getCoinData()
}
You need to update the tableView from the main thread. As a good lesson to learn: Always update the UI from the Main Thread. Always.
do {
self.coins = try JSONDecoder().decode([Coin].self, from: data!)
for info in self.coins {
self.sympolsCoin.append(info.symbol)
self.priceUSDcoin.append(info.price_usd)
DispatchQueue.main.async {
self.tableView.reloadData()
}
print("\(self.sympolsCoin) : \(self.priceUSDcoin)")
completion()
}
}
There is, however another problem with your code the way you have your labels setup won't work. TableViewCells get reused so I'm guessing you have #IBOutlets for them somewhere else. What you should do is declare a label constant in cellForRowAt:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
let coinNameLabel = cell.viewWithTag(100) as! UILabel
coinNameLabel.text = sympolsCoin[indexPath.row]
let priceNameLabel = cell.viewWithTag(101) as! UILabel
priceNameLabel.text = priceUSDcoin[indexPath.row]
}
The above code assumes you've setup two labels with the tags 100 and 101 in your storyboard(assuming your using one)
**
// First View Controller
//
//
//
import UIKit
struct Countory : Decodable {
let name: String
let capital: String
let region: String
let alpha2Code: String
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var listArr = [Countory]()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
let url = "https://restcountries.eu/rest/v2/all"
let urlObj = URL(string: url)!
URLSession.shared.dataTask(with: urlObj) {(data, responds, Error) in
do {
self.listArr = try JSONDecoder().decode([Countory].self, from: data!)
for country in self.listArr {
print("Country",country.name)
print("###################")
print("Capital",country.capital)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
} catch {
print(" not ")
}
}.resume()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.listArr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as! TableViewCell
cell.label1.text = "Name: \(listArr[indexPath.row].name)"
cell.lable2.text = listArr[indexPath.row].capital
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let homeView = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
homeView.res = listArr[indexPath.row].region
homeView.alpha = listArr[indexPath.row].alpha2Code
self.navigationController?.pushViewController(homeView, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
// SecondViewController
class SecondViewController: UIViewController {
#IBOutlet weak var label4: UILabel!
#IBOutlet weak var label3: UILabel!
var res = ""
var alpha = ""
override func viewDidLoad() {
super.viewDidLoad()
self.label3.text = res
self.label4.text = alpha
}
}
**

How to send data to table view with Alamofire And SwiftyJSON

I have a (large amount) of data that I want to send to Table View with alamofire and siftyJSON
web request :
let postEndPoint :String = "http://jsonplaceholder.typicode.com/posts/"
code Alamofire and SwiftyJSON:
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(.GET, postEndPoint).responseJSON { response in
// handle json
guard response.result.error == nil else{
print("error calling Get on /posts/1")
print(response.result.error)
return
}
if let value: AnyObject = response.result.value{
let post = JSON(value)
// for i in 0...post.count{
if let title = post["data"].arrayValue as? [JSON]{
self.datas = title
self.tableView.reloadData()
print("the title is :\(title)" )
}else{
print("eror parsing /post/1 ")
}
// }
}
}
}
code table view :
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell")!
var dict = datas[indexPath.row]
cell.textLabel?.text = dict["userId"] as? String
cell.detailTextLabel?.text = dict["id"] as? String
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datas.count
}
}
web request :enter link description here
I am trying to post some json data to table view but when I send the data it returns nothing . why??
this is the code working for me. main thing is you have to reload the table at the end of api calling. and you are printing nuber as a string so you have to convert it to string
my code is here
import UIKit
class customcell: UITableViewCell {
#IBOutlet weak var lbl1: UILabel!
#IBOutlet weak var lbl2: UILabel!
}
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var tabledata: UITableView!
let postEndPoint :String = "http://jsonplaceholder.typicode.com/posts/"
var arr:NSMutableArray = NSMutableArray()
override func viewDidLoad() {
super.viewDidLoad()
web()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("customcell") as! customcell
let dict = arr[indexPath.row] as! NSDictionary
print(dict)
print(dict["userId"])
cell.lbl1?.text = String (dict["userId"]! )
cell.lbl2?.text = String (dict["id"]! )
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arr.count
}
func web()
{
request(.GET, postEndPoint, parameters: nil, encoding:
.JSON).responseJSON { (response:Response<AnyObject, NSError>) -> Void in
print(response.result.value)
if (response.result.value != nil)
{
self.arr = (response.result.value) as! NSMutableArray
}
self.tabledata.reloadData()
}
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if (tableView == tabledata)
{
let cell = tableView.dequeueReusableCellWithIdentifier("customcell") as! customcell
let dict = arr[indexPath.row] as! NSDictionary
cell.lbl1?.text = String (dict["userId"]! )
cell.selectionStyle = .None
return cell
}
else if(tableView == tablefactoryoption)
{
let cell1:Facturyoptioncell = tableView.dequeueReusableCellWithIdentifier("Facturyoptioncell") as! Facturyoptioncell
let dict = arr[indexPath.row] as! NSDictionary
cell1.lbl2?.text = String (dict["Id"]! )
cell1.selectionStyle = .None
cell1.selectionStyle = .None
return cell1
}
else
{
let cell2:Technicalcell = tableView.dequeueReusableCellWithIdentifier("Technicalcell") as! Technicalcell
let dict = arr[indexPath.row] as! NSDictionary
cell2.lbl3?.text = String (dict["userId"]! )
return cell2
}
}
This is how you can use multiple tableview for display data.