I currently have an array which I am appending options to. They are they displayed in a table with 3 sections. The first 2 sections have 1 row each, but the third section has a variable number of rows depending on what is appended to the array. I essentially take the third component of my initial array (allAlbums[0].markscheme) and break it down to create multiple new items in the array.
However, when I am trying to simulate this, I get a fatal array on 'cell.textData?.text = section[indexPath.row] as! String' and I'm not sure why?
final class CaseViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var titleText: UILabel!
#IBOutlet var tableView: UITableView!
private var allAlbums = [Case]()
let kHeaderSectionTag: Int = 6900;
var expandedSectionHeaderNumber: Int = -1
var expandedSectionHeader: UITableViewHeaderFooterView!
var sectionItems: Array<Any> = []
var sectionNames: Array<Any> = []
var markschemeRows: Array<Any> = []
override func viewDidLoad() {
super.viewDidLoad()
allAlbums = LibraryAPI.shared.getCases()
// Filter the main array to match a single case
allAlbums = allAlbums.filter { $0.title == title}
// Get data to fill in to table
sectionNames = [ "Trainee Information", "Patient Information", "Examiner Information" ];
sectionItems = [ [allAlbums[0].doctor], [allAlbums[0].patient], [allAlbums[0].markscheme]]
let text = allAlbums[0].markscheme
markschemeRows = text.components(separatedBy: " ")
sectionItems.append(contentsOf: markschemeRows)
// Autoresize rows
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 500
// Remove excess row seperators
tableView.tableFooterView = UIView()
tableView.separatorColor = UIColor.clear
titleText.text = title
}
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (self.expandedSectionHeaderNumber == section) {
// Header section
let header = self.sectionNames[section] as! String
// If markscheme, create the markscheme format
if (header == "Examiner Information")
{
print(self.markschemeRows.count)
return self.markschemeRows.count
}
else
{
let arrayOfItems = self.sectionItems[section] as! NSArray
print(arrayOfItems.count)
return arrayOfItems.count
}
} else {
return 0;
}
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if (self.sectionNames.count != 0) {
return self.sectionNames[section] as? String
}
return ""
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44.0;
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat{
return 0;
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
//recast your view as a UITableViewHeaderFooterView
let header: UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView
header.contentView.backgroundColor = UIColor.darkGray
header.textLabel?.textColor = UIColor.white
if let viewWithTag = self.view.viewWithTag(kHeaderSectionTag + section) {
viewWithTag.removeFromSuperview()
}
let headerFrame = self.view.frame.size
let theImageView = UIImageView(frame: CGRect(x: headerFrame.width - 32, y: 13, width: 18, height: 18));
theImageView.image = UIImage(named: "Chevron-Dn-Wht")
theImageView.tag = kHeaderSectionTag + section
header.addSubview(theImageView)
// make headers touchable
header.tag = section
let headerTapGesture = UITapGestureRecognizer()
headerTapGesture.addTarget(self, action: #selector(CaseViewController.sectionHeaderWasTouched(_:)))
header.addGestureRecognizer(headerTapGesture)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! CustomTableCell
let section = self.sectionItems[indexPath.section] as! NSArray
cell.textLabel?.textColor = UIColor.black
cell.textData?.text = section[indexPath.row] as! String
return cell
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
// MARK: - Expand / Collapse Methods
#objc func sectionHeaderWasTouched(_ sender: UITapGestureRecognizer) {
let headerView = sender.view as! UITableViewHeaderFooterView
let section = headerView.tag
let eImageView = headerView.viewWithTag(kHeaderSectionTag + section) as? UIImageView
if (self.expandedSectionHeaderNumber == -1) {
self.expandedSectionHeaderNumber = section
tableViewExpandSection(section, imageView: eImageView!)
} else {
if (self.expandedSectionHeaderNumber == section) {
tableViewCollapeSection(section, imageView: eImageView!)
} else {
let cImageView = self.view.viewWithTag(kHeaderSectionTag + self.expandedSectionHeaderNumber) as? UIImageView
tableViewCollapeSection(self.expandedSectionHeaderNumber, imageView: cImageView!)
tableViewExpandSection(section, imageView: eImageView!)
}
}
}
func tableViewCollapeSection(_ section: Int, imageView: UIImageView) {
let sectionData = self.sectionItems[section] as! NSArray
self.expandedSectionHeaderNumber = -1;
if (sectionData.count == 0) {
return;
} else {
UIView.animate(withDuration: 0.4, animations: {
imageView.transform = CGAffineTransform(rotationAngle: (0.0 * CGFloat(Double.pi)) / 180.0)
})
var indexesPath = [IndexPath]()
for i in 0 ..< sectionData.count {
let index = IndexPath(row: i, section: section)
indexesPath.append(index)
}
self.tableView!.beginUpdates()
self.tableView!.deleteRows(at: indexesPath, with: UITableView.RowAnimation.fade)
self.tableView!.endUpdates()
}
}
func tableViewExpandSection(_ section: Int, imageView: UIImageView) {
let sectionData = self.sectionItems[section] as! NSArray
if (sectionData.count == 0) {
self.expandedSectionHeaderNumber = -1;
return;
} else {
UIView.animate(withDuration: 0.4, animations: {
imageView.transform = CGAffineTransform(rotationAngle: (180.0 * CGFloat(Double.pi)) / 180.0)
})
var indexesPath = [IndexPath]()
// Header section
let header = self.sectionNames[section] as! String
// If markscheme, create the markscheme format
if (header == "Examiner Information")
{
for i in 0 ..< markschemeRows.count {
let index = IndexPath(row: i, section: section)
indexesPath.append(index)
}
}
else
{
for i in 0 ..< sectionData.count {
let index = IndexPath(row: i, section: section)
indexesPath.append(index)
}
}
self.expandedSectionHeaderNumber = section
self.tableView!.beginUpdates()
self.tableView!.insertRows(at: indexesPath, with: UITableView.RowAnimation.fade)
self.tableView!.endUpdates()
}
}
}
The error is pretty clear.
In numberOfRows you return markschemeRows.count for section 2 which is the number of separated items in this line
markschemeRows = text.components(separatedBy: " ")
Then you must also get the item from markschemeRows rather than from section[indexPath.row] in cellForRow
var markschemeRows = [String]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! CustomTableCell
let section = self.sectionItems[indexPath.section] as! NSArray
cell.textLabel?.textColor = UIColor.black
if indexPath.section == 2 {
cell.textData?.text = markschemeRows[indexPath.row]
} else {
cell.textData?.text = section[indexPath.row] as! String
}
return cell
}
Your code is quite cumbersome. For example sectionNames and markschemeRows are clearly [String].Why do you declare the arrays as [Any]? This is Swift. Take care of the types. And don't use Foundation collection types like NSArray in Swift at all. Again take care of the types.
Related
I am developing an app which used table view with multiple section and multiple header view. Is it possible to hide randomly section according to server response, i.e.: I have 6 Multiple cells and header view. I got response from the server which show only 2 sections, 4 section and 6 section. I am trying to achieve this, but didn't get success. Here is my code below:
Code:
var allPermissionSection = ["A","B","C","D","E","F"] // default permission
override func numberOfSections(in tableView: UITableView) -> Int {
return totalSectionTable // total count of showing cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let modelPermission = mainArrayCheckValidations[0] as! MyAcountModel
if section == 0 {
return 1
}
// arraySectionName got from server check index if default section or server reponse index is equal to same then true this continue
if allPermissionSection[0] == arraySectionName[0] {
if arrayTblItems.count > 0 {
return arrayTblItems.count
}else if modelPermission.phoneNumbersEnabled == true {
return 1
}
}
if allPermissionSection[1] == arraySectionName[1] {
if arrayTblItemsForElectronic.count > 0 {
return arrayTblItemsForElectronic.count
}else if modelPermission.econsentEnabled == true {
return 1
}
}
if allPermissionSection[2] == arraySectionName[2] {
if arrayTblItemsForEmergnceContact.count > 0 {
return arrayTblItemsForEmergnceContact.count
}else if modelPermission.emergencyContactsEnabled == true {
return 1
}
}
return 0
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let modelPermission = mainArrayCheckValidations[0] as! MyAcountModel
if indexPath.section == 0 {
return UITableView.automaticDimension
}
if allPermissionSection[0] == arraySectionName[0] {
// if indexPath.section == 1 {
if arrayTblItems.count <= 0 {
if modelPermission.phoneNumbersEnabled == true{
return 40
}else{
return 0
}
}
// }
}
if allPermissionSection[1] == arraySectionName[1] {
// if indexPath.section == 2 {
if arrayTblItemsForElectronic.count <= 0 {
if modelPermission.econsentEnabled == true{
return 40
}else{
return 0
}
}
// }
}
if allPermissionSection[2] == arraySectionName[2] {
// if indexPath.section == 3 {
if arrayTblItemsForEmergnceContact.count <= 0 {
if modelPermission.emergencyContactsEnabled == true{
return 40
}else{
return 0
}
}
// }
}
return UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: USER_DETAIL_CELL, for: indexPath) as! UserDetail_Cell
cell.updateWith(mainArrayCheckValidations[indexPath.row], indexPath.row, mainArrayCheckValidations.count, tblCellType)
return cell
}
if allPermissionSection[0] == arraySectionName[0] {
// if indexPath.section == 1 {
if arrayTblItems.count > 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: PHONE_CELL, for: indexPath) as! PhoneNumberDetailCell
cell.updateWith(arrayTblItems[indexPath.row], indexPath.row, arrayTblItems.count, tblCellType)
return cell
}else{
let cell = tableView.dequeueReusableCell(withIdentifier: DEFAULT_CELL, for: indexPath) as! Default_Custom_Cell
cell.lbl_Name.text = ""
return cell
}
//}
}
if allPermissionSection[1] == arraySectionName[1] {
// if indexPath.section == 2 {
if arrayTblItemsForElectronic.count > 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: CONSTENT_CELL, for: indexPath) as! Constent_Cell
cell.updateWith(arrayTblItemsForElectronic[indexPath.row], indexPath.row, arrayTblItemsForElectronic.count, tblCellType)
return cell
}else{
let cell = tableView.dequeueReusableCell(withIdentifier: DEFAULT_CELL, for: indexPath) as! Default_Custom_Cell
cell.lbl_Name.text = ""
return cell
}
// }
}
if allPermissionSection[2] == arraySectionName[2] {
// if indexPath.section == 3 {
if arrayTblItemsForEmergnceContact.count > 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: EMERGENCY_CONTACT_CELL, for: indexPath) as! EmergencyCnctCell
cell.updateWith(arrayTblItemsForEmergnceContact[indexPath.row], indexPath.row, arrayTblItemsForEmergnceContact.count, tblCellType)
return cell
}else{
let cell = tableView.dequeueReusableCell(withIdentifier: DEFAULT_CELL, for: indexPath) as! Default_Custom_Cell
cell.lbl_Name.text = ""
return cell
}
// }
}
return UITableViewCell()
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
let headerView = setupHeaderView(textHeading: " Details")
return headerView
}
if allPermissionSection[0] == arraySectionName[0] {
//if section == 1 {
let headerView = setupHeaderView(textHeading: "bers")
return headerView
// }
}
if allPermissionSection[1] == arraySectionName[1] {
// if section == 2 {
let headerView = setupHeaderView(textHeading: "sent")
return headerView
// }
}
if allPermissionSection[2] == arraySectionName[2] {
// if section == 3 {
let headerView = setupHeaderView(textHeading: "ontacts")
return headerView
// }
}
return UIView()
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 0 {
return 50
}
if allPermissionSection[0] == arraySectionName[0] {
// if section == 1 {
return 50
// }
}
if allPermissionSection[1] == arraySectionName[1] {
// if section == 2 {
return 50
// }
}
if allPermissionSection[1] == arraySectionName[1] {
// if section == 3 {
return 50
// }
}
return 0
}
setupHeaderView(textHeading:String) -> UIView? {
let headerView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: tblVw.frame.width, height: 50))
let headingLbl = UILabel()
let topLbl = UILabel()
let botomLbl = UILabel()
topLbl.translatesAutoresizingMaskIntoConstraints = false
botomLbl.translatesAutoresizingMaskIntoConstraints = false
headerView.addSubview(botomLbl)
headerView.addSubview(topLbl)
botomLbl.leadingAnchor.constraint(equalTo: headerView.leadingAnchor).isActive = true
botomLbl.trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true
botomLbl.heightAnchor.constraint(equalToConstant:0.5).isActive = true
botomLbl.bottomAnchor.constraint(equalTo: headerView.bottomAnchor).isActive = true
topLbl.leadingAnchor.constraint(equalTo: headerView.leadingAnchor).isActive = true
topLbl.trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true
topLbl.heightAnchor.constraint(equalToConstant:0.5).isActive = true
topLbl.topAnchor.constraint(equalTo: headerView.topAnchor).isActive = true
botomLbl.text = NULL_STRING
topLbl.text = NULL_STRING
topLbl.backgroundColor = .lightGray
botomLbl.backgroundColor = .lightGray
headingLbl.frame = CGRect.init(x: 0, y: 0, width: headerView.frame.width, height: headerView.frame.height)
headingLbl.text = textHeading
headingLbl.textColor = UIColor(hexString: "587358")
headerView.backgroundColor = UIColor(displayP3Red: 245/256, green: 245/256, blue: 245/256, alpha: 0.6)
headingLbl.textAlignment = .center
headerView.addSubview(headingLbl)
return headerView
}
So, Here is the my code please let me know if i m doing wrong please correct me
Can someone please explain to me hide or show randomly section,
Any help would be greatly appreciated.
Thanks in advance.
class AllDetailAccount {
var HeaderName: String?
var HeaderDeatil: [Any]?
init(HeaderName: String, HeaderDeatil: [Any]) {
self.HeaderName = HeaderName
self.HeaderDeatil = HeaderDeatil
}
}
class UnitUserDetail: AbstractController {
var allAcountDetailInfo = [AllDetailAccount]()
override func numberOfSections(in tableView: UITableView) -> Int {
return allAcountDetailInfo.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if allAcountDetailInfo[section].HeaderName == "USERDETAIL_STRING" {
return 1
}else if allAcountDetailInfo[section].HeaderName == "PHONE_NUMBR_STRING" {
let modelDate = allAcountDetailInfo[section].HeaderDeatil?[0] as! [PhoneNumber]
if modelDate.count == 0 {
return 1
}
return modelDate.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if allAcountDetailInfo[indexPath.section].HeaderName == "USERDETAIL_STRING" {
let modelDate = allAcountDetailInfo[indexPath.section].HeaderDeatil![0] as! UnitUserDetailModel
let cell = tableView.dequeueReusableCell(withIdentifier: "USER_DETAIL_CELL", for: indexPath) as! UserDetail_Cell
cell.updateWith(modelDate, indexPath.row, 0, tblCellType)
return cell
}else if allAcountDetailInfo[indexPath.section].HeaderName == "PHONE_NUMBR_STRING" {
let modelDate = allAcountDetailInfo[indexPath.section].HeaderDeatil?[0] as! [PhoneNumber]
let cell = tableView.dequeueReusableCell(withIdentifier: "PHONE_CELL", for: indexPath) as! PhoneNumberDetailCell
cell.updateWith(modelDate[indexPath.row], indexPath.row, modelDate.count, tblCellType)
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "DEFAULT_CELL", for: indexPath) as! Default_Custom_Cell
return cell
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 40))
view.backgroundColor = UIColor(displayP3Red: 245/256, green: 245/256, blue: 245/256, alpha: 0.6)
let lbl = UILabel(frame: CGRect(x: 15, y: 0, width: view.frame.width - 15, height: 40))
lbl.font = UIFont.systemFont(ofSize: 20)
lbl.text = allAcountDetailInfo[section].HeaderName
lbl.textAlignment = .center
lbl.textColor = UIColor(hexString: "HEADER_LABLE_TEXT_COLOUR")
let topLbl = UILabel()
view.addSubview(topLbl)
topLbl.translatesAutoresizingMaskIntoConstraints = false
topLbl.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
topLbl.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
topLbl.heightAnchor.constraint(equalToConstant:0.5).isActive = true
topLbl.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
topLbl.backgroundColor = .lightGray
topLbl.text = NULL_STRING
view.addSubview(lbl)
return view
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
}
I have 3 arrays of data. I want to show ads after every 5 user cells in the table.
var nativeAds = [GADNativeAd]()
var item = [NewsElement]()
var filterItem = [NewsElement]()
After displaying 5 cells with ads, the application crashes with an error "Thread 1: Fatal error: Index out of range"
How do I re-add ads to the array or select an array with ads again?
There are smart guys sitting here, please help me. Thank you in advance!
below is my code
extension NewsViewController: GADNativeAdLoaderDelegate {
func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
print("\(adLoader) failed with error: \(error.localizedDescription)")
}
func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) {
print("Received native ad: \(nativeAd)")
nativeAds.append(nativeAd)
}
func adLoaderDidFinishLoading(_ adLoader: GADAdLoader) {
newsTblView.reloadData()
}
}
extension NewsViewController: UITableViewDelegate, UITableViewDataSource {
private func dataRow(for indexPath: IndexPath) -> Int? {
let (quotient, remainder) = (indexPath.row + 1).quotientAndRemainder(dividingBy: numAdsToLoad)
if remainder == 0 { return nil }
return quotient * (numAdsToLoad - 1) + remainder - 1
}
private func adRow(for indexPath: IndexPath) -> Int? {
let (quotient, remainder) = (indexPath.row + 1).quotientAndRemainder(dividingBy: numAdsToLoad)
if remainder != 0 { return nil }
return quotient - 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchActive {
return filterItem.count
} else {
return item.count + nativeAds.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let row = dataRow(for: indexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "NewsTableViewCell", for: indexPath) as! NewsTableViewCell
if searchActive {
let items = filterItem[row]
cell.configCell(model: items )
} else {
let items = item[row]
cell.configCell(model: items )
}
cell.selectionStyle = .none
cell.backgroundColor = .clear
return cell
} else if let row = adRow(for: indexPath) {
let nativeAd = nativeAds[row] <-- "Thread 1: Fatal error: Index out of range"
nativeAd.rootViewController = self
let nativeAdCell = tableView.dequeueReusableCell(withIdentifier: "UnifiedNativeAdCell", for: indexPath) as! GADNativeAdViewCell
nativeAdCell.setAdData()
return nativeAdCell
}
fatalError("Did not find data or ad for cell: Should never get here")
}
}
I have tableView with one cell which contains one label.. i need to display different label text for different category.
for that i have created empty iteamArray and i am trying to append iteamArray for different category using if condition. in the same way i need to return array count in numberOfRowsInSection but here i am unable to check if condition, it only goes out side return if i give return iteamArray.count then it displays all category values if i give return 0 it display nothing in tableview.
if i click water i need to show only water related iteamsArray in tabelview.. but here if i click any category it shows all category related values in tableview.. please help me in the code.
here is my code:
import UIKit
class PaymentTableViewCell: UITableViewCell{
#IBOutlet weak var pamntTypeLabel: UILabel!
}
class AllMakePaymentViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var categoryName: String?
var iteamsArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
allPaymentService()
}
func allPaymentService(){
let urlStr = "https://dev.com/webservices/api.php?rquest"
let url = URL(string: urlStr)
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
guard let respData = data else {
return
}
guard error == nil else {
print("error")
return
}
do{
let jsonObj = try JSONSerialization.jsonObject(with: respData, options: .allowFragments) as! [String: Any]
//print("the all make payment json is \(jsonObj)")
let billerdetailsArray = jsonObj["billerdetails"] as! [[String: Any]]
for billerdetail in billerdetailsArray {
self.categoryName = billerdetail["bcategoryname"] as? String
if self.categoryName == "Water"{
let bName = billerdetail["bname"] as? String
self.iteamsArray.append(bName ?? "")
print("water arry \(self.iteamsArray.append(bName ?? ""))")
}
if self.categoryName == "Landline Postpaid"{
let bName = billerdetail["bname"] as? String
self.iteamsArray.append(bName ?? "")
print("Landline arry \(self.iteamsArray.append(bName ?? ""))")
}
if self.categoryName == "DTH"{
let bName = billerdetail["bname"] as? String
self.iteamsArray.append(bName ?? "")
print("DTH arry \(self.iteamsArray.append(bName ?? ""))")
}
if self.categoryName == "Electricity"{
let bName = billerdetail["bname"] as? String
self.iteamsArray.append(bName ?? "")
print("Electricity arry \(self.iteamsArray.append(bName ?? ""))")
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
catch {
print("catch error")
}
}).resume()
}
}
extension AllMakePaymentViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if categoryName == "Water"{
return iteamsArray.count
}
if categoryName == "Landline Postpaid"{
return iteamsArray.count
}
if categoryName == "DTH"{
return iteamsArray.count
}
if categoryName == "Electricity"{
return iteamsArray.count
}
return iteamsArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! PaymentTableViewCell
cell.pamntTypeLabel.text = iteamsArray[indexPath.row]
self.tableView.separatorStyle = .none
return cell
}
}
Please help me in above code.
This as you embed all the items to the same array here
if self.categoryName == "Water"{
let bName = billerdetail["bname"] as? String
self.iteamsArray.append(bName ?? "")
print("water arry \(self.iteamsArray.append(bName ?? ""))")
}
if self.categoryName == "Landline Postpaid"{
let bName = billerdetail["bname"] as? String
self.iteamsArray.append(bName ?? "")
print("Landline arry \(self.iteamsArray.append(bName ?? ""))")
}
if self.categoryName == "DTH"{
let bName = billerdetail["bname"] as? String
self.iteamsArray.append(bName ?? "")
print("DTH arry \(self.iteamsArray.append(bName ?? ""))")
}
if self.categoryName == "Electricity"{
let bName = billerdetail["bname"] as? String
self.iteamsArray.append(bName ?? "")
print("Electricity arry \(self.iteamsArray.append(bName ?? ""))")
}
Even categoryName is different , instead you better need
var iteamsArray = [Category]()
var filteredArray = [Category]()
guard let res = try? JSONDecoder().decode(Root.self,from:data) else { return }
self.iteamsArray = res.billerdetails
struct Root {
let billerdetails:[Category]
}
struct Category {
let bcategoryname,bname:String
}
Then use filteredArray for the table and when you need to change category do
self.filteredArray = itemsArray.filter{ $0.bcategoryname == "Water" }
self.tableView.reloadData()
I created an array that is filled from a JSON file. When I try to fill the table view with the array's items, it shows the last record repeatedly even though indexPath.row is returning correctly.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return leagueStandingsModelArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellTeam", for: indexPath)
let team = self.leagueStandingsModelArray[indexPath.row]
cell.textLabel?.text = String(team.teamId)
print(team.teamName)
print(indexPath.row)
return cell
}
On my debug window, this is the result I am getting:
There are my array items printed
1 -- Santos -- 32
2 -- Palmeiras -- 28
3 -- Flamengo -- 24
4 -- Atletico-MG -- 24
And this is the return I get from these two lines below
print(team.teamName)
print(indexPath.row)
Atletico-MG
0
Atletico-MG
1
Atletico-MG
2
Atletico-MG
3
Should be printing the first four teams and not the fourth four times.
Full Code
import UIKit
import Alamofire
import SwiftyJSON
class LeagueOverviewViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let leagueModel = LeagueIdModel()
var leagueParams = LeagueParametersModel()
var leagueStandingsModelArray = [LeagueStandingsModel]()
var urls = URLs()
#IBOutlet weak var standingsTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return leagueStandingsModelArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellTeam", for: indexPath)
let team = self.leagueStandingsModelArray[indexPath.row]
cell.textLabel?.text = String(team.teamId)
print(leagueStandingsModelArray[0].teamName)
print(leagueStandingsModelArray[1].teamName)
print(leagueStandingsModelArray[2].teamName)
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
getLeagueIdJSON(country: leagueParams.country, season: leagueParams.season)
standingsTableView.delegate = self
standingsTableView.dataSource = self
}
//GET THE JSON FILE TO RETRIEVE LEAGUE ID USING COUNTRY AND SEASON AS PARAMETERS
func getLeagueIdJSON (country: String, season: Int) {
let headers = Headers().getHeaders()
let url = urls.getLeagueUrlByCountryAndSeason(country: leagueParams.country, season: leagueParams.season)
Alamofire.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers).responseJSON {
response in
if response.result.isSuccess {
let leagueJSON = JSON(response.result.value!)
self.getLeagueId(json: leagueJSON, country: self.leagueParams.country, season: self.leagueParams.season)
self.getLeagueStandings(leagueId: self.leagueModel.leagueId)
}
}
}
//GET LEAGUE_ID FROM JSON FILE RETRIEVED
func getLeagueId(json: JSON, country: String, season: Int) {
var leagueId = 0
if country == "gb" {
for league in json["api"]["leagues"].arrayValue {
if league["name"].stringValue == "Premier League" {
leagueId = league["league_id"].intValue
}
}
}
else if country == "br" {
for league in json["api"]["leagues"].arrayValue {
if league["name"].stringValue == "Serie A" {
leagueId = league["league_id"].intValue
}
}
}
leagueModel.leagueId = leagueId
}
//GET LEAGUE STANDINGS FROM A LEAGUE ID (TOP 4)
func getLeagueStandings (leagueId: Int) {
let headers = Headers().getHeaders()
let url = urls.getLeagueStandingsUrl(leagueId: leagueId)
let leagueStandingsModel = LeagueStandingsModel()
var counter = 0
Alamofire.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers).responseJSON {
response in
if response.result.isSuccess {
let standingsJSON = JSON(response.result.value!)
for standings in standingsJSON["api"]["standings"][counter].arrayValue {
if counter <= 3 {
leagueStandingsModel.teamId = standings["team_id"].intValue
leagueStandingsModel.rank = standings["rank"].intValue
leagueStandingsModel.teamName = standings["teamName"].stringValue
leagueStandingsModel.points = standings["points"].intValue
leagueStandingsModel.matchesPlayed = standings["all"]["matchsPlayed"].intValue
leagueStandingsModel.win = standings["all"]["win"].intValue
leagueStandingsModel.draw = standings["all"]["draw"].intValue
leagueStandingsModel.lose = standings["all"]["lose"].intValue
leagueStandingsModel.goalsFor = standings["all"]["goalsFor"].intValue
leagueStandingsModel.goalsAgainst = standings["all"]["goalsAgainst"].intValue
self.leagueStandingsModelArray.append(leagueStandingsModel)
let standings = String(self.leagueStandingsModelArray[counter].rank) + " -- " +
self.leagueStandingsModelArray[counter].teamName + " -- " +
String(self.leagueStandingsModelArray[counter].points)
print(standings)
counter += 1
}
}
}
self.standingsTableView.reloadData()
}
}
}
Instead of reusing let leagueStandingsModel = LeagueStandingsModel() create new object right before populating it:
if counter <= 3 {
var leagueStandingsModel = LeagueStandingsModel()
leagueStandingsModel.teamId = standings["team_id"].intValue
...
I have table view which displays a list of items. Every time a row is selected, a checkmark is added, a corresponding amount is added to var total.
If another row is selected the checkmark of the previous row is removed,the amount for the previous row is subtracted.
I am trying to save and retrieve to/from NSUserdefaults the following info:
checkmark of the row selected (if any was selected),
value for var total,
indexPathForCellSelected,
,amount for the specific row that was selected.
import UIKit
class EighthViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {
struct Item {
var name:String // name of the row
var selected:Bool // whether is selected or not
var amount: Int // value of the item
}
var frequency = [
Item(name:"Every week",selected: false, amount: 30),
Item(name:"Every 2 weeks",selected: false, amount: 30),
Item(name:"Every 4 weeks",selected: false, amount: 30),
Item(name:"Once",selected: false, amount: 40),
Item(name:"End of tenancy cleaning", selected: false, amount: 44)
]
var total = 0
var indexPathForCellSelected: NSIndexPath?
#IBOutlet weak var tableView: UITableView!
let indexKey = "indexPathForCellSelected"
let totalKey = "total"
let amountKey = "amount"
override func viewDidLoad() {
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// retrieve indexPathForCellSelected from NSUserDefaults
if let retrievedIndexPath = NSUserDefaults.standardUserDefaults().objectForKey(indexKey) {
let data1 = NSUserDefaults.standardUserDefaults().objectForKey(indexKey) as? NSData
indexPathForCellSelected = NSKeyedUnarchiver.unarchiveObjectWithData(data1!) as? NSIndexPath
// retrieve total from NSUserDefaults
if let totalRetrieved = NSUserDefaults.standardUserDefaults().objectForKey(totalKey) as? Int {
total = totalRetrieved
print(total)
}
//
if let itemAmount = NSUserDefaults.standardUserDefaults().objectForKey(amountKey) as? Int {
let myIndexpath = indexPathForCellSelected?.row
frequency[myIndexpath!].amount = itemAmount
**UPDATED:** tableView.cellForRowAtIndexPath(indexPathForCellSelected!)?.accessoryType = .Checkmark
}
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return frequency.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
// configure the cell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")
cell?.textLabel?.text = frequency[indexPath.row].name
return cell!
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if !frequency[indexPath.row].selected {
// this avoid set initial value for the first time
if let index = indexPathForCellSelected {
// clear the previous cell
frequency[index.row].selected = false
tableView.cellForRowAtIndexPath(index)?.accessoryType = .None
self.total -= frequency[index.row].amount
print(total)
}
// mark the new one
frequency[indexPath.row].selected = true
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .Checkmark
indexPathForCellSelected = indexPath
self.total += frequency[indexPath.row].amount
print(total)
if indexPathForCellSelected != nil { // check if there is a selected row in the table
//save indexPathForCellSelected in NSUserDefaults
let data = NSKeyedArchiver.archivedDataWithRootObject(indexPathForCellSelected!)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: indexKey)
//save total in NSUserDefaults
NSUserDefaults.standardUserDefaults().setObject(total, forKey: totalKey)
// save amount in NSUserDefaults
NSUserDefaults.standardUserDefaults().setObject(frequency[indexPath.row].amount, forKey: amountKey)
} // end of if indexPathForCellSelected
}
}
}
here is screenshot from the app : link
This code works. If anyone has a better implementation, please post it in the answer section.
class EighthViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {
struct Item {
var name:String // name of the row
var selected:Bool // whether is selected or not
var amount: Int // value of the item
}
var frequency = [
Item(name:"Every week",selected: false, amount: 30),
Item(name:"Every 2 weeks",selected: false, amount: 30),
Item(name:"Every 4 weeks",selected: false, amount: 30),
Item(name:"Once",selected: false, amount: 40),
Item(name:"End of tenancy cleaning", selected: false, amount: 44)
]
var total = 0
var indexPathForCellSelected: NSIndexPath?
#IBOutlet weak var tableView: UITableView!
let indexKey = "indexPathForCellSelected"
let totalKey = "total"
let amountKey = "amount"
override func viewDidLoad() {
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// retrieve indexPathForCellSelected from NSUserDefaults
if let retrievedIndexPath = NSUserDefaults.standardUserDefaults().dataForKey(indexKey) {
if let data1 = NSKeyedUnarchiver.unarchiveObjectWithData(retrievedIndexPath) as? NSIndexPath{
indexPathForCellSelected = data1
}
// retrieve total from NSUserDefaults
if let totalRetrieved = NSUserDefaults.standardUserDefaults().objectForKey(totalKey) as? Int {
total = totalRetrieved
print(total)
}
//
if let itemAmount = NSUserDefaults.standardUserDefaults().objectForKey(amountKey) as? Int {
let myIndexpath = indexPathForCellSelected?.row
frequency[myIndexpath!].amount = itemAmount
tableView.cellForRowAtIndexPath(indexPathForCellSelected!)?.accessoryType = .Checkmark
}
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return frequency.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
// configure the cell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")
cell?.textLabel?.text = frequency[indexPath.row].name
return cell!
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if !frequency[indexPath.row].selected {
// this avoid set initial value for the first time
if let index = indexPathForCellSelected {
// clear the previous cell
frequency[index.row].selected = false
tableView.cellForRowAtIndexPath(index)?.accessoryType = .None
self.total -= frequency[index.row].amount
print(total)
}
// mark the new one
frequency[indexPath.row].selected = true
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .Checkmark
self.total += frequency[indexPath.row].amount
indexPathForCellSelected = indexPath
print(total)
if indexPathForCellSelected != nil { // check if there is a selected row in the table
//save indexPathForCellSelected in NSUserDefaults
let data = NSKeyedArchiver.archivedDataWithRootObject(indexPathForCellSelected!)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: indexKey)
//save total in NSUserDefaults
NSUserDefaults.standardUserDefaults().setObject(total, forKey: totalKey)
// save amount in NSUserDefaults
NSUserDefaults.standardUserDefaults().setObject(frequency[indexPath.row].amount, forKey: amountKey)
} // end of if indexPathForCellSelected
}
}
}