TableView With 3 Sections and cells crashing - swift

I have a simple UITableViewController with 3 sections and each section has 3 rows. I have already allocated each cell it's reuse identifier.
When I run the code, I get an EXE_BAD_INSTRUCTION error at return cell.
Here is my code:
import UIKit
class settingsViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 3
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : UITableViewCell!
if indexPath.section == 1
{
if indexPath.row == 1
{
cell = tableView.dequeueReusableCellWithIdentifier("draftCell", forIndexPath: indexPath) as UITableViewCell
}
else if indexPath.row == 0
{
cell = tableView.dequeueReusableCellWithIdentifier("profileCell", forIndexPath: indexPath) as UITableViewCell
}
else if indexPath.row == 2
{
cell = tableView.dequeueReusableCellWithIdentifier("logoutCell", forIndexPath: indexPath) as UITableViewCell
}
}
else if indexPath.section == 2{
if indexPath.row == 0
{
cell = tableView.dequeueReusableCellWithIdentifier("facebookCell", forIndexPath: indexPath) as UITableViewCell
}
else if indexPath.row == 1
{
cell = tableView.dequeueReusableCellWithIdentifier("twitterCell", forIndexPath: indexPath) as UITableViewCell
}
else if indexPath.row == 2
{
cell = tableView.dequeueReusableCellWithIdentifier("rateusCell", forIndexPath: indexPath) as UITableViewCell
}
}
else if indexPath.section == 3
{
if indexPath.row == 0
{
cell = tableView.dequeueReusableCellWithIdentifier("creditsCell", forIndexPath: indexPath) as UITableViewCell
}
else if indexPath.row == 1
{
cell = tableView.dequeueReusableCellWithIdentifier("contactusCell", forIndexPath: indexPath) as UITableViewCell
}
else if indexPath.row == 2
{
cell = tableView.dequeueReusableCellWithIdentifier("termsandconditionsCell", forIndexPath: indexPath) as UITableViewCell
}
}
return cell
}

For section number 0 you haven't written cellForRowAtIndexPath. You have given number of sections = 3, so its index starts from 0,
Correct your indexpath.section comparison i.e do it for indexpath.section == 0, indexpath.section == 1 and indexpath.section == 2.
Also you haven't registered class for tableview cell like
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")

You would be better off using a static tableView in storyboard, instead of trying to programmatically code static cells in an dynamic tableView.
Apple's Table View Programming Guide recommends:
Use static cells to design a table with a fixed number of rows, each with its own layout. Use static cells when you know what the table looks like at design time, regardless of the specific information it displays.
If you are determined to dynamically handle this, your code would be easier to read and maintain if you used a switch statement, instead of nested ifs.

You have 3 sections but the index should start from 0 (0,1,2,3,...). So modify your code starting from indexPath.section == 0 (which is the first section of your table). Furthermore I agree with PetahChristian that you may use static cell to design your table.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : UITableViewCell!
if indexPath.section == 0
{
if indexPath.row == 1
{
cell = tableView.dequeueReusableCellWithIdentifier("draftCell", forIndexPath: indexPath) as UITableViewCell
}
else if indexPath.row == 0
{
cell = tableView.dequeueReusableCellWithIdentifier("profileCell", forIndexPath: indexPath) as UITableViewCell
}
else if indexPath.row == 2
{
cell = tableView.dequeueReusableCellWithIdentifier("logoutCell", forIndexPath: indexPath) as UITableViewCell
}
}
else if indexPath.section == 1{
if indexPath.row == 0
{
cell = tableView.dequeueReusableCellWithIdentifier("facebookCell", forIndexPath: indexPath) as UITableViewCell
}
else if indexPath.row == 1
{
cell = tableView.dequeueReusableCellWithIdentifier("twitterCell", forIndexPath: indexPath) as UITableViewCell
}
else if indexPath.row == 2
{
cell = tableView.dequeueReusableCellWithIdentifier("rateusCell", forIndexPath: indexPath) as UITableViewCell
}
}
else if indexPath.section == 2
{
if indexPath.row == 0
{
cell = tableView.dequeueReusableCellWithIdentifier("creditsCell", forIndexPath: indexPath) as UITableViewCell
}
else if indexPath.row == 1
{
cell = tableView.dequeueReusableCellWithIdentifier("contactusCell", forIndexPath: indexPath) as UITableViewCell
}
else if indexPath.row == 2
{
cell = tableView.dequeueReusableCellWithIdentifier("termsandconditionsCell", forIndexPath: indexPath) as UITableViewCell
}
}
return cell
}

Related

Display three reusbale cells in tableview - Swift 5

I have 3 UITableViewCell with XIB files but on my tableview I can't display my three UITableViewCell, only can load the first two
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (indexPath.item % 2 == 0) {
let cell = tableView.dequeueReusableCell(withIdentifier: "CaptureNameTableViewCell", for: indexPath) as! CaptureNameTableViewCell
cell.nameTextField.text = ""
cell.nameTextField.tag = indexPath.row
cell.nameTextField.delegate = self
return cell
} else if indexPath.section == 2 {
let cell = tableView.dequeueReusableCell(withIdentifier: "CapturePhotoTableViewCell", for: indexPath) as! CapturePhotoTableViewCell
cell.displayImage = imageView
cell.cellDelegate = self
cell.selectImage.tag = indexPath.row
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "PieChartTableViewCell", for: indexPath) as! PieChartTableViewCell
return cell
}
}
You need to register the xib tableViewCells inside of the tableViewController:
First create an id property inside of the cells xib class, to use as the cell’s reuse identifier (make the name of this the same as your reuse identifier for the cell which you set in the xib file):
let id = "cellIdentifier" // Name this appropriately
Then create a nib method inside of the cell's xib class:
func nib() -> UINib {
return UINib(named: "cellIdentifier", bundle: nil)
}
Then inside of a lifecycle method such as viewDidLoad():
tableView.register(nib: cell.nib, forCellReuseIdentifier: cell.id)
Finally, specify which cells you want to be where in the table view at which indexPath.row. (Which row in the table view):
switch indexPath.row {
case 0: // First cell
let cell = tableView.dequeueReusableCell(withIdentifier: "CaptureNameTableViewCell", for: indexPath) as! CaptureNameTableViewCell
// Configure cell as before
return cell
case 1: // Second cell
let cell = tableView.dequeueReusableCell(withIdentifier: "CapturePhotoTableViewCell", for: indexPath) as! CapturePhotoTableViewCell
// Configure cell as before
return cell
case 2: // Third cell
let cell = tableView.dequeueReusableCell(withIdentifier: "PieChartTableViewCell", for: indexPath) as! PieChartTableViewCell
// Configure cell as before
return cell
default:
return UITableViewCell() // This should not be reached but a switch statement must cover all possibilities.
}

Swift - Table View - Repeat order of different sections for multiple data

I have a table with four different sections. After I fetch data from the database and store them in an array, I want to display them in the table view. This means, for each object, I will extract information and put it into the correct section of the table view.
To describe it more simple:
Object 1
TableViewCell 1
TableViewCell 2
TableViewCell 3
TableViewCell 4
Object 2
TableViewCell 1
TableViewCell 2 ..
Currently, my approach looks like
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->
UITableViewCell {
let participationObject = Participation(json: (hitsSource?.hit(atIndex: indexPath.row))!)
checkIfUserAlreadyRatedForParticipationContent(participationObject: participationObject)
if (indexPath.section == 0 || indexPath.section % 4 == 0) {
let userProfileCell = tableView.dequeueReusableCell(withIdentifier: "userProfileCell", for: indexPath) as! ChallengeInfoUserTableViewCell
self.dataAccessService.fetchUserById(completionHandler: { (challengeOrganizer) in
let cell = tableView.cellForRow(at: indexPath) as! ChallengeInfoUserTableViewCell
userProfileCell.fullNameLabel.text = challengeOrganizer.firstName + " " + challengeOrganizer.lastName
userProfileCell.fetchProfileImageOfUser(userObject: challengeOrganizer)
userProfileCell.fetchNumberOfWonChallengesByOrganizerId(challengeOrganizer: challengeOrganizer)
userProfileCell.starNumberLabel.text = challengeOrganizer.stars
userProfileCell.delegate = self
}, uid: participationObject.userId)
return userProfileCell
}
else if (indexPath.section % 4 == 1) {
let challengeImageCell = tableView.dequeueReusableCell(withIdentifier: "challengeImageCell", for: indexPath) as! ChallengeInfoImageTableViewCell
dataAccessService.fetchParticipationImageByParticipantIdChallengeId(completionHandler: { (participationImage) in
let cell = tableView.cellForRow(at: indexPath) as! ChallengeInfoImageTableViewCell
challengeImageCell.checkIfToAddOrRemovePlayIcon(participationObject: participationObject)
challengeImageCell.setChallengeImage(challengeImage: participationImage)
challengeImageCell.delegate = self
challengeImageCell.moreButton.tag = indexPath.row
}, participantId: participationObject.userId, challengeId: challengeObject.id)
return challengeImageCell
}
else if (indexPath.section % 4 == 2) {
let commentCell = tableView.dequeueReusableCell(withIdentifier: "commentCell", for: indexPath) as! ChallengeContentDetailCommentTableViewCell
commentCell.fetchCommentsByParticipationId(participationObject: participationObject)
return commentCell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func numberOfSections(in tableView: UITableView) -> Int {
return (hitsSource?.numberOfHits())! * 4
}
I have two issues:
1.) I get always the same object from my data source
2.) When calling let cell = tableView.cellForRow(at: indexPath) as! ChallengeInfoImageTableViewCell It crashes at some point.
Is my approach even legit? Is it clean?
This depends on the data array and you are ignoring the section parameter in numberOfSections(in:)
Never retrieve data asynchronously in cellForRow and update the cell by calling tableView.cellForRow(at:. Cells can be moved off screen immediately so there is no cellForRow(at.
Note:
The first expression in (indexPath.section == 0 || indexPath.section % 4 == 0) is redundant. indexPath.section % 4 is 0 if section is 0.

Refactoring TableView with multiple cell types

Any suggestions regarding factoring a massive view controller, with multiple cell types, cell sizes. Because each cell has its own delegates, the view controller becomes super confusing when navigating through the file.
Or is this the standard approach to for multiple cell types? How would you go about building multiple with multiple sections & cells. Much thanks!
//Rows
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 && sectionArray[0].isExpanded {
return sectionArray.count
} else if section == 0 && sectionArray[0].isExpanded == false {
return sectionArray[0].section.count - 1
}
if section == 1 {
return 3
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 && indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "CreateFavoriteIconCell", for: indexPath) as! CreateFavoriteIconCell
cell.delegate = self
return cell
}
if indexPath.section == 1 {
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "CreateFavoritePhotoCell", for: indexPath) as! CreateFavoritePhotoCell
cell.delegate = self
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "CreateFavoriteLocationCell", for: indexPath) as! CreateFavoriteLocationCell
return cell
case 2:
let cell = tableView.dequeueReusableCell(withIdentifier: "CreateFavoriteDescriptionCell", for: indexPath) as! CreateFavoriteDescriptionCell
return cell
default:
return tableView.cellForRow(at: indexPath)!
}
}
return tableView.cellForRow(at: indexPath)!
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
switch indexPath.row {
case 0:
tableView.rowHeight = 58
default:
tableView.rowHeight = 0
}
}
if indexPath.section == 1 {
switch indexPath.row {
case 0:
tableView.rowHeight = 120
case 1:
tableView.rowHeight = 60
case 2:
tableView.rowHeight = 160
default:
tableView.rowHeight = 0
}
}
return tableView.rowHeight
}

swift UICollectionViewCell text is not appearing in UICollectionView with two custom cell

I'm trying to make a timetable app with UICollectionView.
So I made a two custom cell class, TimeTableCell and TimeTableDescriptionCell.
TimeTableCell has two label to present the subject name and classroom.
TiemTableDescriptionCell is for the first section and the first row, to present the day of the week and the time.
I just simply dragged the UICollectionViewCell in UICollectionView in the storyboard, and designed two cells and connected each of them with TimeTableCell and TimeTableDescriptionCell.
The two cell's identifier is diffrent.
This is my collectionView(collectionView: , cellForItemAtIndexPath: )
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
print("\(indexPath.section), \(indexPath.row)")
let dayArray = ["", "월", "화", "수", "목", "금"]
let cell: UICollectionViewCell!
if indexPath.section == 0 {
// Day
cell = collectionView.dequeueReusableCellWithReuseIdentifier("TimeTableDescriptionCell", forIndexPath: indexPath) as! TimeTableDescriptionCell
cell.contentView.layer.borderWidth = 1
cell.contentView.layer.borderColor = UIColor.blackColor().CGColor
(cell as! TimeTableDescriptionCell).titleLabel!.text = "월"
return cell
} else if indexPath.row == 0 {
// index
cell = collectionView.dequeueReusableCellWithReuseIdentifier("TimeTableDescriptionCell", forIndexPath: indexPath) as! TimeTableDescriptionCell
cell.contentView.layer.borderWidth = 1
cell.contentView.layer.borderColor = UIColor.blackColor().CGColor
(cell as! TimeTableDescriptionCell).titleLabel.text = "1"
return cell
} else {
cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! TimeTableCell
if let timeTableElement = self.timeTable[indexPath.section-1][indexPath.row-1] {
(cell as! TimeTableCell).subjectNameLabel.text = timeTableElement.subjectName
(cell as! TimeTableCell).subjectNameLabel.adjustsFontSizeToFitWidth = true
(cell as! TimeTableCell).classRoomLabel.text = timeTableElement.classRoom
(cell as! TimeTableCell).classRoomLabel.adjustsFontSizeToFitWidth = true
} else {
(cell as! TimeTableCell).subjectNameLabel.text = ""
(cell as! TimeTableCell).classRoomLabel.text = ""
}
cell.contentView.layer.borderWidth = 1
cell.contentView.layer.borderColor = UIColor.blackColor().CGColor
print("class")
return cell
}
return cell
}
and this is my storyboard.
my storyboard
When I debugg, the TimeTableCells are showing nice.
But the TimeTableDescriptionCells are not appearing like this.
debugg
In the first section and the first row, there should be the day of the week and the time.
How can I fix this?
EDIT:
My other functions of UICollectionViewDataSource is
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
if timeTableData == nil {
return 0
}
return self.timeTable.count+1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if timeTableData == nil {
return 0
}
return self.timeTable[0].count+1
}
func collectionView(collectionView: UICollectionView, didEndDisplayingCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
if indexPath.section == 0 {
}
}
I wan't to fill the first section with "Mon", "Tue"... and first row with 1,2,3,4,...

How to add two custom cell into tableview in storyboard in Swift?

I have a tableView with two different custom cell. One cell have a switch and other a image, I have Two separated custom class for the cells, identifiers.. but I can't see this. i don't know if I need change the configuration in story board to dynamic or other thing.. Can I show two different custom cells
Thanks!
Check the criteria for showing each specific custom cell, then cast to that cell as needed:
override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
if (criteria for cell 1) {
let cell = tableView!.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as? Cell1
return (cell)
}
else {
let cell = tableView!.dequeueReusableCellWithIdentifier("cell2", forIndexPath: indexPath) as? Cell2
return (cell)
}
}
Swift 3
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath -> UITableViewCell {
if (criteria for cell 1) {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as! Cell1
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath) as! Cell2
return cell
}
}
override func tableView(tableView: UITableView?,cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
if (...) {
let cell : Mycell1 = tableView!.dequeueReusableCellWithIdentifier("Mycell1", forIndexPath: indexPath) as? Mycell1
return cell
}
else {
let cell : Mycell2 = tableView!.dequeueReusableCellWithIdentifier("Mycell2", forIndexPath: indexPath) as? Mycell2
return cell
}
}