TableView Json Array - json

{
"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
}

Related

Nested struct for UITableView Swift/JSON

I need to display topic and description in a UITableView.
struct Topics: Decodable {
let subtopics: [subTopic]
struct subTopic: Decodable {
var topic = ""
var description = ""
}
}
The data for the TableView is fetched with a URL post request and assigned inside a do/try/catch block.
let Topics = Topics()
excerpt from URLRequest:
self.Topics = try JSONDecoder().decode(Topics.self, from: data)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "topicCell") as! topicCell
var subTopic = Topics?.subtopics[indexPath.row]
cell.topicLabel?.text = subTopic.topic
cell.descriptionTextView?.text = subTopic.description
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Topics?.subtopics.count
}
Sample JSON:
{"subtopics":[{"topic":"Computer Science", "description":"beginner course"},{"topic":"Data Analysis", "description":"beginner course"}]}
You give the the variable the same name as the struct.
let Topics = Topics()
Don't do that. It is confusing and can cause unexpected behavior.
There is a reason for the naming convention to name variables lowercase and structs/classes uppercase.
For less confusion name the top object different for example
struct Response: Decodable {
let subtopics: [SubTopic]
struct SubTopic: Decodable {
let topic, description : String
}
}
The default values (and variables) in SubTopic make no sense.
My next recommendation is to omit the top object and declare the data source array
var subTopics = [Response.SubTopic]()
and assign
let response = try JSONDecoder().decode(Response.self, from: data)
self.subTopics = response.subtopics
This will clean up the table view code and gets rid of the ugly optionals
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "topicCell") as! topicCell
let subTopic = subTopics[indexPath.row]
cell.topicLabel?.text = subTopic.topic
cell.descriptionTextView?.text = subTopic.description
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return subTopics.count
}

Unable to show all JSON response values in Collectionview(ERROR: Index out of range) in Swift

I am using collectionview in tableview cell.. here i want to show tableview cells one value in collectionview.. but all the time i am getting only one filename value even it has array of values
my JSON response in console:
JSON: {
result = {
bids = (
{
"get_attachments" = (
{
filename = "1627385763-6142.png";
},
{
filename = "1627388474-7134.jpeg";
},
{
filename = "1627398168-8608.jpeg";
}
);
"get_bid_user" = {
fname = "new user";
gender = M;
};
},
{
"get_attachments" = (
{
filename = "1627387642-9066.jpg";
}
);
"get_bid_user" = {
fname = Akash;
gender = M;
};
}
);
model for JSON
public class ViewProposalResult {
public var bids : Array<Bid>?
}
public class Bid {
public var get_attachments : Array<Get_attachments>?
}
public class Get_attachments {
public var filename : String?
}
here i want get_attachments all filename values in collectionview.. how?
for tableview and collectionview code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ViewProposalTableVIewCell", for: indexPath) as! ViewProposalTableVIewCell
var bidData = viewproposalData?.result?.bids?[indexPath.row]
cell.bidAttatchment = bidData?.get_attachments
cell.attetchmentsCollectionview.reloadData()
return cell
}
//collectionview code
class ViewProposalTableVIewCell: UITableViewCell, UICollectionViewDelegate,UICollectionViewDataSource {
#IBOutlet weak var attetchmentsCollectionview: UICollectionView!
public var bidAttatchment: Array<Get_attachments>?
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return bidAttatchment?[section].filename?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BidAttatchmentCollectionViewCell", for: indexPath) as! BidAttatchmentCollectionViewCell
var attatchBid = bidAttatchment?[indexPath.item]//getting error "Index out of range:"
cell.attatchmentLbl.text = attatchBid?.filename
return cell
}
error:
Fatal error: Index out of range
where am i wrong. please do guide me
First of all consolidate the naming of the variables to make clearer what is a single object and what is an array.
Replace bidAttatchment with attachments (plural form)
Replace Get_attachments with Attachment (singular form)
Declare the array as non-optional empty array. The benefit is you get rid of all the question marks
Then in numberOfItemsInSection just return the number of items in attachments. Your data source doesn't contain sections so the section parameter is irrelevant.
class ViewProposalTableVIewCell: UITableViewCell, UICollectionViewDelegate,UICollectionViewDataSource {
#IBOutlet weak var attetchmentsCollectionview: UICollectionView!
public var attachments = Array<Attachment>()
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return attachments.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BidAttatchmentCollectionViewCell", for: indexPath) as! BidAttatchmentCollectionViewCell
let attatchBid = attachments[indexPath.item]
cell.attatchmentLbl.text = attatchBid.filename
return cell
}

Unable to Expand and Collapse TableViewCell in Swift

I have taken two prototype cells called CategoryTableCell and SubCategoryTableCell in tableview
Initially, I need to show all CategoryTableCell data in TableView. Here if I click CategoryTableCell then I need to show that Category's subcategories in SubCategoryTableCell. How to do that?
I need to hide all subcategories. If I click any one category from CategoryTableCell then I need to its subcategories.
Code:
extension CategoryVC: UITableViewDelegate, UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return self.activeCategories?.count ?? 0 : 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.activeCategories?[section].sub_categories?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubCategoryTableCell", for: indexPath) as! SubCategoryTableCell
cell.selectionStyle = .none
let activesubCat = self.activeCategories?[indexPath.section].sub_categories
let indexData = activesubCat?[indexPath.row]
cell.lblTitle?.text = langType == .en ? indexData?.details?.first?.title : indexData?.details?[1].title
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = tableView.dequeueReusableCell(withIdentifier: "CategoryTableCell") as! CategoryTableCell
let indexData = self.activeCategories?[section]
view.btnDetails?.tag = section
view.lblTitle?.text = langType == .en ? indexData?.details?.first?.title : indexData?.details?[1].title
return view
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return isFromFilter ? 40 : 0
}
With the code, I am getting all categories in red colour and subcategories in dark grey colour text. But, here cell is not expanding and collapse. I need to show all red colour text initially. Here if I tap on the cell then it has to expand and show all grey colour text. How to do that? Please do help with the code.
o/p: coming like this with above code
[![screenshot][1]][1]
EDIT
JSON Model:
public class Category_json {
public var id : Int?
public var status : String?
public var sub_categories : Array<Sub_categories>?
var isExpanded = true
required public init?(dictionary: NSDictionary) {
id = dictionary["id"] as? Int
status = dictionary["status"] as? String
if (dictionary["sub_categories"] != nil) { sub_categories = Sub_categories.modelsFromDictionaryArray(array: dictionary["sub_categories"] as? NSArray ?? NSArray()) }
if (dictionary["details"] != nil) { details = Details.modelsFromDictionaryArray(array: dictionary["details"] as? NSArray ?? NSArray()) }
}
public func dictionaryRepresentation() -> NSDictionary {
let dictionary = NSMutableDictionary()
dictionary.setValue(self.id, forKey: "id")
dictionary.setValue(self.status, forKey: "status")
return dictionary
}
}
and public var activeCategories : Array<Category_json>?
EDIT2:
#objc func expandMe() {
print("expand me")
}
Add a property to your activeCategories array 's model
var isExpanded = true
Then inside numberOfRowsInSection
guard let item = self.activeCategories?[section] else { return 0 }
return item.isExpanded ? (item.sub_categories?.count ?? 0) : 0
Then play with isExpanded and refresh the table
Edit
Inside viewForHeaderInSection
let header = tableView.dequeueReusableCell(withIdentifier: "CategoryTableCell") as! CategoryTableCell
button.tag = section
Then inside action
#objc headerClicked(_ sender:UIButton) {
let section = sender.tag
guard let item = self.activeCategories?[section] else { return 0 }
item.isExpanded.toggle()
tableView.reloadData()
}

My textlabel and detailtextLabel display the same text

Iphone screenshot
https://i.stack.imgur.com/zQ06M.png
I'm trying to make it so that my textLabel and my detailTextLabel show two different things but for some reason they both say the same thing. There should be just one cell here with the top label displaying the number 2 and the bottom label displaying the ;slakdfj(random typing for now). Refer to the links above for screenshot.
here is the main vc:
import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase
import FirebaseStorage
class ListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableViewProducts: UITableView!
var delegate: ListViewController?
var ref:DatabaseReference?
var databaseHandle: DatabaseHandle?
var postData = [productsList]()
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference().child("0")
loadProducts()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postData.count
}
func loadProducts() {
ref?.observe(DataEventType.value, with: { (snapshot) in
var newSweets = [productsList]()
for post in snapshot.children {
let postObject = productsList(snapshot: post as! DataSnapshot)
newSweets.append(postObject)
print(self.postData)
}
self.postData = newSweets
self.tableViewProducts.reloadData()
}) { (error:Error) in
print(error)
}
}
//This places the text on the ViewControllerTableViewCell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let sweet = postData[indexPath.row]
cell.textLabel?.text = sweet.id
cell.detailTextLabel?.text = sweet.p_name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showDetails", sender: self)
}
}
here is the structure:
import Foundation
import UIKit
import FirebaseDatabase
struct productsList {
let id: String!
let p_name: String!
init(id: String, p_name: String) {
self.id = id
self.p_name = p_name
}
init (snapshot:DataSnapshot) {
id = snapshot.value as! String
p_name = snapshot.value as! String
}
}
Data Structure(is pretty basic for now):
[ {
"id" : "2",
"p_name" : ";slakdfj"
} ]
Here you set the same value into id and p_name.
That's the reason.
init (snapshot:DataSnapshot) {
id = snapshot.value as! String
p_name = snapshot.value as! String
}
You need to change this code something like this:
init (snapshot:DataSnapshot) {
var dict = snapshot.value as! [String: AnyObject]
id = dict["id"] as! String
p_name = dict["p_name"] as! String
}
Here you need to change "id" and "p_name" to fit your firebase database.

JSON displayed to tableview

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.