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")
}
}
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 this code, where I have 2 Json arrays which I try to compare in my code -> all and allUrl. When array all contains some id from array allUrl image table row should be change to red, or vice versa green.
According this results I want to change label text, label text color, label text font size, but when I run app, label text still "PASSED" and gray, thanks.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
let listOfStudentsUrl = allUrl.reduce(into: [String:String]()){$0[$1.id] = $1.timestampValue}
// Compare data
listOfStudentsUrl.forEach { key in print(key)
if all[indexPath.row].id == key.key {
cell.textLabel?.text = all[indexPath.row].id
cell.detailTextLabel?.text = all[indexPath.row].timestampValue
cell.imageView!.image = UIImage(named:"red_icon")
cell.isHidden = false
statusLabel.text = "NOT PASSED"
statusLabel.textColor = UIColor.red
statusLabel.font = statusLabel.font.withSize(35)
break
} else {
statusLabel.text = "PASSED"
statusLabel.textColor = UIColor.gray
statusLabel.font = statusLabel.font.withSize(35)
cell.isHidden = true
}
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var rowHeight:CGFloat = 0.0
let listOfStudentsUrl = allUrl.reduce(into: [String:String]()){$0[$1.id] = $1.timestampValue}
for key in listOfStudentsUrl{
if all[indexPath.row].id == key.key {
rowHeight = 49.0
break
} else {
rowHeight = 0.0
}
}
return rowHeight
}
Json format:
{
"class": {
"studentOne": {
"stringValue": "2020-02-04"
},
"studentTwo ": {
"stringValue": "2020-02-05"
}
},
"createTime": "2020-03-30",
"updateTime": "2020-03-30"
}
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 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.
I have a tableview in which the first cell is different from all the others (I have two custom cells in the table dequeued With different Identifiers). The codes are as below:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("profileCell") as! SbProfileViewCell
//cell.textArea.text = bio[indexPath.row]
//pictureFile[indexPath.row].getDataInBackgroundWithBlock { (fileData, error) -> Void in
if let pic = UIImage(data: fileData!) {
cell.imageView.image = pic
}
}
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("postCell") as! SbPostsTableViewCell
cell.date.text = dateFormatter.stringFromDate(dates[indexPath.row - 1])
pictureFileOne[indexPath.row - 1].getDataInBackgroundWithBlock { (fileOneData, error) -> Void in
if let downloadedImageOne = UIImage(data: fileOneData!) {
cell.imageArea.image = downloadedImageOne
}
}
cell.textArea.text = text[indexPath.row - 1]
return cell
}
}
i'm getting the array out of index error for the commented lines and i'm also uncertain about whether using [indexPath.row - 1] would yield the effect I want (I want the second cell of the tableview to display the first object in the array), hope i explained everything ok, please help! thanks
EDIT
var dates = [NSDate]()
var autoBio = [String]()
func getPosts() {
let getPostsQuery = PFQuery(className: "allPosts")
getPostsQuery.whereKey("userId", equalTo: userNumber)
getPostsQuery.limit = 15
getPostsQuery.orderByDescending("createdAt")
getPostsQuery.findObjectsInBackgroundWithBlock { (posts, error) -> Void in
if let posts = posts {
self.dates.removeAll(keepCapacity: true)
for post in posts {
self.dates.append(post.createdAt as NSDate!)
}
}
print(self.dates.count)
}
}
func getBio() {
let bioQuery = PFQuery(className: "bios")
bioQuery.whereKey("userId", equalTo: userNumber)
bioQuery.limit = 1
bioQuery.findObjectsInBackgroundWithBlock { (bios, error) -> Void in
if let bios = bios {
self.bio.removeAll(keepCapacity: false)
for bio in bios {
self.bio.append(bio["about"] as! String)
}
}
}
print(self.bio.count)
}
i put getPosts() and getBio() in viewDidLoad. And I tried printing the bio and dates count as the end of these func and they do return a number > 0 so the arrays should be filled. Any idea what's wrong?
You should try using the first cell as Section Header cell...
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCellWithIdentifier("profileCell") as! SbPostsTableViewCell
return cell
}