Index out of range in tableView - ios

I am trying to display 2 different types of data in table view. The videoNews Array only has one element that is to be displayed in indexPath.row == 1 and Suggested News array has many elements that are to be displayed in indexPath.row >= 4. Everything in between are just labels and go as it is. The problem comes when elements from SuggestedNews array are displayed the tableView gives index out of range error even though the array has elements and numberOfRowsInSection also gets the right number of elements.
Code of TableView
var SuggestedNews = [VideoNews]()
var videoNews = [VideoNews]()
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (5 + SuggestedNews.count)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
if let cell = tableView.dequeueReusableCell(withIdentifier: "VideoArticleCell", for: indexPath) as? VideoArticleCell {
let video = self.videoNews[indexPath.row]
cell.updateUI(video: video)
return cell
}
} else if indexPath.row == 1 {
if let cell = tableView.dequeueReusableCell(withIdentifier: "VideoFirstLabelCell") {
return cell
}
} else if indexPath.row == 2 {
if let cell = tableView.dequeueReusableCell(withIdentifier: "VideoSubmissionCell", for: indexPath) as? VideoSubmissionCell {
return cell
}
} else if indexPath.row == 3 {
if let cell = tableView.dequeueReusableCell(withIdentifier: "VideoSecondLabelCell") {
return cell
}
} else if indexPath.row >= 4 {
if let cell = tableView.dequeueReusableCell(withIdentifier: "VideoSuggestionCell", for: indexPath) as? VideoSuggestionCell {
let latest = self.SuggestedNews[indexPath.row] //Index out of range
cell.updateUI(latest: latest)
return cell
}
}
return UITableViewCell()
}

If index.row == 4 your code in this line but you want to show first element of array; therefore, your first array index is equal to 0.
let latest = self.SuggestedNews[indexPath.row - 4]
If you have 4 cell different than SuggestedNews, your return don't be return (5 + SuggestedNews.count)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (4 + SuggestedNews.count)
}

Related

How to add different cell to tableview?

I have a tableview and I'm downloading data from firebase after that I reload tableview but I want to add more different cell to tableview too. For example my datas count is six and I want to add to second row and fifth row different cell. In the end I want to show eight cell.
I tried this code;
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 1 {
let cell = myTableView.dequeueReusableCell(withIdentifier: "makeLiveWallpaper") as! LiveWallTableViewCell
if indexPath.row == 1 {
cell.titleLabel.text = "Let's make LiveWallpaper"
}
return cell
}else{
if let cell = myTableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell", for: indexPath) as? CategoryTableViewCell{
cell.category = category(at: indexPath)
cell.delegate = self
cell.setScrollPosition(x: offsets[indexPath] ?? 0)
return cell
}
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 1 {
return 140
}else{
return 255
}
}
But it is not adding new cell it is over write on cell
Once you got the data update your dataSource like given below:
data.insert("", at: 1)
data.insert("", at: 4)
self.tableView.reloadData()
update your Data Source Method
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 1 {
// your custom Cell
return cell
} else if indexPath.row == 5 {
// you custom Cell
return cell
} else {
// normal cell
}
return UITableViewCell()
}
Hope it will hep you.

TableView cells from different sections getting mixed up

I am trying to implement a tableview with two sections. Each section has one type of cell which will be needed.
So section one cells are subclassed as PendingTVC
section two cells are subclassed as ScheduledCell.
I have the follow methods implemented but the cells are getting mixed up. For example if section one has 3 cells, the first 3 cells in section 2 have a mixed up label which correlates to section one's first 3 cells. Code below:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if arr != nil {
if section == 0 {
print("returning pending : \(pendingCount)")
return pendingCount
}
else{
print("returning scheduled count : \(scheduledCount)")
return scheduledCount
}
}
return 0
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Pending"
}
else{
return "Scheduled"
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50.0
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let data = arr![indexPath.row]
if indexPath.section == 0 {
if let cell = tableView.dequeueReusableCell(withIdentifier: "Pending") as? PendingTVC{
PendingTVC.formattCell(cell: cell, data: data)
cell.selectionStyle = .none;
cell.delegate = self
return cell
}
}
else{
if let cell = tableView.dequeueReusableCell(withIdentifier: "scheduledCell") as? ScheduledCell{
print("cellforrowat in scheduledCell")
ScheduledCell.formatCell(cell: cell, data: data)
cell.selectionStyle = .none;
return cell
}
}
return UITableViewCell()
}
You should fetch your data inside your section condition. If you fetch data beforehand its ambiguous with indexpath data you require.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
if indexPath.section == 0 {
if let cell = tableView.dequeueReusableCell(withIdentifier: "Pending") as? PendingTVC{
let data = pendingarr![indexPath.row] //access pending data here
PendingTVC.formattCell(cell: cell, data: data)
cell.selectionStyle = .none;
cell.delegate = self
return cell
}
}
else{
if let cell = tableView.dequeueReusableCell(withIdentifier: "scheduledCell") as? ScheduledCell{
print("cellforrowat in scheduledCell")
let data = scheduledarr![indexPath.row] // access scheduled arr here
ScheduledCell.formatCell(cell: cell, data: data)
cell.selectionStyle = .none;
return cell
}
}
}
You're using the same data array for for both sections.
let data = arr![indexPath.row]
Here you can see you are referencing indexPath.row as your index within your data array. This means the section is irrelevant. You have at least two options...
Create a 2d array in which the first index value is your section and the second is the row. e.g. dataArray = [[test, test2, test3], [otherTest, otherTest2, otherTest3]]. This can be accessed by changing your line to:
let data = arr![indexPath.section][indexPath.row]
or
2. Create two separate arrays... one for section 1 and one for section 2. Call them within your relevant checks for sections.

Multiple TableView Custom Cells

So i have created a table view with 2 custom cells.
i am trying to enter data into the 3rd cell, but im having a problem when returning how many cells & also to make my title array commence from my 3rd cell.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var row = indexPath.row
if(row == sliderIndex){
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! Row
return cell
}else if (row == instagramIndex) {
var cell2 = tableView.dequeueReusableCell(withIdentifier: "instgramCell", for: indexPath) as! Insta
return cell2
} else {
var cell3 = tableView.dequeueReusableCell(withIdentifier: "blogCell", for: indexPath) as! blogCell
if (row == 3) {
cell3.blogTitle.text = titleArray[0]
}
return cell3
}
In last case, row is impossible to equal to 3. Change it to 2.
You return 3 in func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int). So value of row only would be [0, 1, 2]
And according to your code, you might make a mistake that set sliderIndex to 1 and set instagramIndex to 2. They should be 0 and 1.

How to custom order two different sections in a tableview Swift

I have successfully implemented two different sections in my table view. Section 1 has 3 cells displayed first, then section 2 has 12 displayed afterwards.
I would like to have it ordered so section 1 has its 3 cells mixed into section 2 (12 cells) So in this case it would be displayed every 4 cells. I would like to code it in a way that when the section 2 cells increases over time it keeps section 1 every 4 cells.
Here is the tableview delegate functions I have at the moment
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 2
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
if (section == 0) {
return 3 // At the moment I have hard coded it will change it to array.count
} else {
return eventNameArray.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("MovingCell", forIndexPath: indexPath) as! WhatsOnMovingTableViewCell
// Do something!
return cell
}
else {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! WhatsOnTableViewCell
// Do something!
return cell
}
}
You cannot mix the cells of different sections.
Since that is what you want the solution is to remove the sections all together or include more sections:
Solution 1:
1 Section with x cells: Cell|Cell|Cell|Cell|MovingCell|Cell|Cell|Cell|Cell|Moving Cell
Solution 2: y Sections with 1 or z cells - Cell|Cell|Cell|Cell + MovingCell + Cell|Cell|Cell|Cell + Moving Cell
I will show you the code that would be needed for Solution 1. You will need to have some variable indicating what the length of Cell-semi-sections would be, e.g. let cellCountBeforeMoving = 4:
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3 + eventNameArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if (indexPath.item + 1) % (cellCountBeforeMoving + 1) == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("MovingCell", forIndexPath: indexPath) as! WhatsOnMovingTableViewCell
// Do something!
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! WhatsOnTableViewCell
// Do something!
return cell
}
}
Note the indexes are now a little offset and you have to be careful accessing the array. The probably correct way to get the element corresponding to a given indexPath is
eventNameArray[indexPath.item - ((indexPath.item + 1) / (cellCountBeforeMoving + 1))]
Solution 1 will end up something like: (you need some var which gives you the number of interplaced MovingCells)
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return movingCells * 2
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section % 2 == 1 {
return 1
}
return cellCountBeforeMoving
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.section % 2 == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("MovingCell", forIndexPath: indexPath) as! WhatsOnMovingTableViewCell
// Do something!
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! WhatsOnTableViewCell
// Do something!
return cell
}
}

Display show more in uitableview

By default each section should show maximum three cells. If any cell contains more than three cells, it should display 'show more' option.If show more is tapped I want to display the rest of the cells in that particular section. Two days I spent, nothing worked out.Segments at the top of the table. Depend on segment selected, tableview load the cells. This code for each segment each section varies, so the func cellForRowAtIndexPath: becomes big seriously very big. I roughly added code. This code is what i have tried.
if segmentName == .Feature || segmentName == .Services
{
if indexPath.section == 0
{
if boolShowFullFeature[indexPath.section] == false
{
if indexPath.row == showCells
{
return createShowMoreCell(indexPath.section)
}
else
{
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! SearchListViewCell
var firstTitle = "", secondTitle = "", thirdTitle = "", recomendValue = "", starValue = ""
(firstTitle, secondTitle, thirdTitle, recomendValue, starValue) = model.foodValue[indexPath.row]
cell.configureCell(firstTitle, secondTitle: secondTitle, thirdTitle: thirdTitle, recomendValue: recomendValue, starValue: starValue)
return cell
i had actually done this before. here is sample code:
var objects = [["1","2","3"],["q","w","e","r","t","y"],["z","x","c","v","b","n","m"]]
var sec = ["sec a","sec b","sec c"]
var showallSec = 0
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sec.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let items = objects[section].count
if items > 3{
if section == showallSec-1{
return items
}
return 4
}
return items
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
let object = objects[indexPath.section][indexPath.row]
cell.textLabel!.text = object
if(indexPath.section != showallSec-1){
if(indexPath.row == 3){
cell.textLabel!.text = "show more"
}}
return cell
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sec[section]
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if(indexPath.row == 3){
showallSec = indexPath.section + 1
tableView.reloadData()
}
}

Resources