I want to use AlamofireObjectMapper for the first time to parse a json response in swift.
I mapped it like this:
class ModelCurrency: Mappable {
var success : Bool?
var terms : String?
var privacy : String?
var timestamp : CGFloat?
var source : String?
var quotes : [Quotes]?
init() {}
required init?(map: Map) {
}
func mapping(map: Map) {
success<-map["success"]
terms<-map["terms"]
privacy<-map["privacy"]
timestamp<-map["timestamp"]
source<-map["source"]
quotes<-map["quotes"]
print("It json\(terms)")
}
}
class Quotes : Mappable {
var name : String?
var val : CGFloat?
required init?(map: Map) {
}
func mapping(map: Map) {
name<-map["name"]
val<-map["val"]
}
}
and my controller
var arrayTable = [String]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
super.viewDidLoad()
let URL = "http://www.apilayer.net/api/live?access_key=ad847a0a855c0647590df2b818923025"
Alamofire.request(URL).responseObject { (response: DataResponse<ModelCurrency>) in
let currency = response.result.value!;
for quotes in currency.quotes! {
self.arrayTable.append(quotes.name!)
}
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 5}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayTable.count }
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell", for: indexPath) as UITableViewCell
cell.textLabel?.text = self.arrayTable[indexPath.row]
return cell
}
I want array quotes displayed in tableview. How to do it ?
I think you need to reload table view after you updated the data source arrayTable:
...
for quotes in currency.quotes! {
self.arrayTable.append(quotes.name!)
}
self.tableView.reloadData()
...
Besides, you don't need to call super.viewDidLoad() twice.
Related
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.
initially I am able to show all rows in tableview.. now i need to show only searched textfield rows...
here the textfield and search button is outside the tableview.. now if i add date in textfield and tap on search button then i need to show only the date contain row only in tableview how to do that
code to show all rows in tableview: here in postedServicesCall param's from_date is nil then i need to show all rows .. which i am able to do with below code.. now how to show if there is a value in from_date then only the date contained rows in tableview
class PageContentViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var fromDateTextField: MDCTextField!
private var servicesArray = [ServicesModel]()
override func viewDidLoad() {
postedServicesCall()
DispatchQueue.main.async {
self.servicesTableView.reloadData()
}
}
func postedServicesCall(){
let param = ["from_date" : ""]
APIReqeustManager.sharedInstance.serviceCall(param: param as [String : Any], method: .post, loaderNeed: false, loadingButton: nil, needViewHideShowAfterLoading: nil, vc: self, url: CommonUrl.posted_requests, isTokenNeeded: true, isErrorAlertNeeded: true, isSuccessAlertNeeded: false, actionErrorOrSuccess: nil, fromLoginPageCallBack: nil) { [weak self] (resp) in
self?.postedServicesData = Posted_services_base_model(dictionary: resp.dict as NSDictionary? ?? NSDictionary())
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return servicesArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ServicesTableViewCell", for: indexPath) as! ServicesTableViewCell
cell.serviceTitle.text = servicesArray[indexPath.row].title
cell.dateLabel.text = servicesArray[indexPath.row].date
cell.locationLabel.text = servicesArray[indexPath.row].location
return cell
}
//if i add date in textfield and tap on search.. then with the date how many rows are there should be display in tableview
#IBAction func searchtBtn(_ sender: TransitionButton) {
}
if i search date in textfield then i need to show the date related rows in tableview.. how?
please do help with code
try this easy search implementation
//
// ViewController.swift
//
// Created by Rajesh Gandru on 4/12/21.
//
import UIKit
//MARK:- User Model Class
struct User {
var userName: String?
var userNumber : String?
var UserAge : String?
}
//MARK:- tableview cell
class ExampleCell:UITableViewCell{
#IBOutlet weak var resultLBLref:UILabel!
}
class ViewController: UIViewController {
//MARK:- Class Outlets...
#IBOutlet weak var searchtextfeildref: UITextField!
#IBOutlet weak var tableViewref: UITableView!
//MARK:- Class Properties...
var listArr : [User] = []
var filteredlistArr :[User] = []
var searchMyOrders = false
//MARK:- View Lyfe cycle starts here..
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.listArr = [User(userName: "Raj", userNumber: "78623", UserAge: "34"),User(userName: "Ram", userNumber: "67467645", UserAge: "22"),User(userName: "Raki", userNumber: "5634534", UserAge: "43"),User(userName: "Raksha", userNumber: "098098", UserAge: "18"),User(userName: "Ravi", userNumber: "7863846", UserAge: "24")]
self.searchtextfeildref.addTarget(self, action: #selector(self.textFieldDidChange(_:)),
for: UIControl.Event.editingChanged)
}
//MARK:- Textfeild Search
#objc func textFieldDidChange(_ textField: UITextField) {
// filter tableViewData with textField.text
let searchText = textField.text
//by_bus_cities_drop_address
filteredlistArr = self.listArr.filter {
return (($0.userName?.localizedLowercase.contains(searchText!))! ||
$0.userNumber!.localizedLowercase.contains(searchText!))
} ?? []
if(filteredlistArr.count == 0){
searchMyOrders = false;
} else {
searchMyOrders = true;
}
self.tableViewref.reloadData()
}
}
//MARK:- Tableview Content
extension ViewController : UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchMyOrders {
return filteredlistArr.count
}else {
return listArr.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:ExampleCell = tableView.dequeueReusableCell(withIdentifier: "ExampleCell", for: indexPath) as! ExampleCell
if searchMyOrders {
cell.resultLBLref.text = filteredlistArr[indexPath.row].userName
}else {
cell.resultLBLref.text = listArr[indexPath.row].userName
}
return cell
}
}
I'm starting on swift and I'm trying to bring a list of cars with alamofire but it is not bringing
The code executes without throwing errors but not the list
I see a blank table view
https://uploaddeimagens.com.br/imagens/simulator_screen_shot_-_iphone_8_-_2019-10-20_at_16-48-23-png
(sorry... editing with the write code)
My classes
struct HotelData: Codable {
let results: [Results]
}
struct Results: Codable {
let smallDescription: String
let price: Price
let gallery: [ImageHotel]
let name: String
let address: Address
var getRandonImage: ImageHotel {
let index = Int(arc4random_uniform(UInt32(gallery.count)))
return gallery[index]
}
}
==============
My manager
class func getHotels(onComplete: #escaping (HotelData?) -> Void) {
AF.request(path).responseJSON { (response) in
guard let jsonData = response.data else { return }
guard let hotelData = try? JSONDecoder().decode(HotelData.self, from: jsonData)
else {
onComplete(nil)
return
}
onComplete(hotelData)
return
}
}
}
==============
Cell
func prepareCell(with hotel: Results){
lbName.text = hotel.name
lbSmallDescription.text = hotel.smallDescription
lbPrice.text = "R$ \(hotel.price.amount)"
lbAdress.text = hotel.address.city
}
==============
TableView
class HotelTableViewController: UITableViewController {
var hotels: [Results] = []
let hotelManager = HotelManager()
override func viewDidLoad() {
super.viewDidLoad()
loadHotels()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return hotels.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HotelTableViewCell
let hotel = hotels[indexPath.row]
cell.prepareCell(with: hotel)
return cell
}
func loadHotels() {
HotelManager.getHotels { (hotelData) in
if let hotelData = hotelData {
self.hotels += hotelData.results
}
}
}
}
Your direct issue is that you need to call reloadData() if you want your UITableView to look at your downloaded data and load the appropriate cells. You can put in the completion handler of your network call, or in a didSet on your hotels property.
Additionally, you shouldn't use responseJSON for Decodable types, it's redundant. Instead you should use responseDecodable and pass the type you want to parse: responseDecodable(of: HotelData.self) { response in ... }.
....................................................................................................................................................................
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
{
"YASSINIRLA" : "True",
"KARBON" : "98",
"GRUP" : "Orta Boy",
"INDIRIMORANI" : "0",
"KLIMA_TR" : "Var",
"KREDI_FIYAT" : "107",
"SIRANO" : "1",
"YAKIT_EN" : "Diesel",
}
Hi. I solved the problem but it is too long. I created an array for all of them. I also showed it in table view. How can I make it shorter? Sorry for my English. Thanks.
dizi1.append(arac["YASSINIRLA"].string!)
dizi2.append(arac["KARBON"].string!)
dizi3.append(arac["INDIRIMORANI"].string!)
dizi4.append(arac["KLIMA_TR"].string!)
dizi5.append(arac["KREDI_FIYAT"].string!)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return diziAracModelii.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "sonAracListelee") as! sonAracListeleViewCell
cell.lblAracAdi1.text = dizi1[indexPath.row]
cell.lblAracAdi2.text = dizi2[indexPath.row]
cell.lblAracAdi3.text = dizi3[indexPath.row]
cell.lblAracAdi4.text = dizi4[indexPath.row]
cell.lblAracAdi5.text = dizi5[indexPath.row]
return cell
}
An easier thing to do is to make a struct model, where you declare the variables. Then you can make an initiator function where you initiates the variables with the data from the json object. I recommend using SwiftyJSON while doing this.
If let in the init function make sure to check if the object contains any value.
struct CustomModel {
public private(set) var yassinirla: String?
public private(set) var karbon: String?
public private(set) var indirimorani: String?
public private(set) var klimaTr: String?
public private(set) var krediFiyat: String?
init(arac: JSON) {
if let yassinirla = arac["YASSINIRLA"].string {
self.yassinirla = yassinirla
}
if let karbon = arac["KARBON"].string {
self.karbon = karbon
}
if let indirimorani = arac["INDIRIMORANI"].string {
self.indirimorani = indirimorani
}
if let klimaTr = arac["KLIMA_TR"].string else {
self.klimaTr = klima_tr
}
if let krediFiyat = arac["KREDI_FIYAT"].string else {
self.krediFiyat = krediFiyat
}
}
}
In the header you can declare your array diziAracModelii as [CustomModel] so you don't have to use separate arrays for each string. That's just bad practice. You can handle this with a single array.
diziAracModelii: [CustomModel] = [CustomModel]()
func grabJson() {
//...Download the json into a json constant
//Send in the jsonobject in the CustomModel
let newObject = CustomModel(arac: json)
//Append to your string and make sure to reload the tableView data.
diziAracModelii.append(newObject)
self.yourTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return diziAracModelii.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "sonAracListelee") as sonAracListeleViewCell else { return UITableViewCell() }
cell.lblAracAdi1.text = diziAracModelii[indexPath.row].yassinirla
cell.lblAracAdi2.text = diziAracModelii[indexPath.row].karbon
cell.lblAracAdi3.text = diziAracModelii[indexPath.row].indirimorani
cell.lblAracAdi4.text = diziAracModelii[indexPath.row].klimaTr
cell.lblAracAdi5.text = diziAracModelii[indexPath.row].krediFiyat
return cell
}