UITableView won't see custom UITableViewCell

I just made a second UITableViewCell class, and my table view won't see it when I try to instantiate it! Here's my cell class:


import UIKit

class RecordingCell: UITableViewCell {
    
    
    @IBOutlet var titleLabel: UILabel!
    var title : String = ""
    
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        title = titleLabel.text!
        
        titleAnimation()
        
    }
    
    
    
    func titleAnimation(){
        print ("starting the animation function")
        UIView.animate(withDuration: 1.5, delay: 1.5, options: .curveEaseInOut, animations: {
            
            self.titleLabel.text! = "Recording in Progress"
    
        }, completion: nil)
    }
}


It's super simple and just something I'm playing with. And here's how I'm filling the table view:


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        if videoURLS.count == 0{
            selectButton.isEnabled = false
            let cell = tableView.dequeueReusableCell(withIdentifier: "emptyCell")
            return cell!
        }
            
        if tableView.numberOfRows(inSection: 0) == (videoURLS.count + 1){
            if indexPath.row == 0{
                let cell = self.tableView.dequeueReusableCell(withIdentifier: "recordingCell") as! RecordingCell
                return cell
            }
            if indexPath.row != 0{
                selectButton.isEnabled = true
                let cell = self.tableView.dequeueReusableCell(withIdentifier: "videoCell") as! VideoCell
                cell.videoURL = videoURLS[indexPath.row - 1]
                cell.parent = self
                cell.setViews()
                cell.setString()
                cell.setDate()
                cell.setTitle()
                cell.setSize()
                cell.setJpg()
                return cell
            }
        }
        else{
            selectButton.isEnabled = true
            let cell = self.tableView.dequeueReusableCell(withIdentifier: "videoCell") as! VideoCell
            cell.videoURL = videoURLS[indexPath.row]
            cell.parent = self
            cell.setViews()
            cell.setString()
            cell.setDate()
            cell.setTitle()
            cell.setSize()
            cell.setJpg()
            return cell
        }
    }


At line 11 it shows the error "Use of undeclared type RecordingCell." I've tried resetting the target in the cell class, but it still doesn't work.

Replies

What happens if you add another RecordingCell class to your target.


RecordingCell2.swift

import UIKit

class RecordingCell {}


This sort of issue happens when Target Membership setting of the source file is not checked. If you have confirmed it's checked, some internal data structure of Xcode may be broken.

I made a new subclass of UITableViewCell :


import UIKit

class RecordingCell2: UITableViewCell {

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}


Same thing. The same error message. I'll try opening the project on another computer later and see if that works.

I wanted you to check if you could find a Duplicate Definition error or not...


Anyway when you find other info please share.

By the way, do you use some Pods (or other packages managed by a 3rd party manager)?

Yeah, I'm using one pod, but it hasn't caused any issues.

OK, I opened the file on another computer, and it still doesn't see the cell subclass. I'm also getting another error message at the bottom of the ..cellForRowAt.. function. It says "Missing return in a function expected to return UITableViewCell." I am so confused right now. The "Else" statement should take care of that! What's going on?!

Would you post the complete code of cellForRowAt func ?


of course, else must return a UITableViewCell()

Here it is again:


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        if videoURLS.count == 0{
            selectButton.isEnabled = false
            let cell = tableView.dequeueReusableCell(withIdentifier: "emptyCell")
            return cell!
        }
            
        if tableView.numberOfRows(inSection: 0) == (videoURLS.count + 1){
            if indexPath.row == 0{
                let cell = self.tableView.dequeueReusableCell(withIdentifier: "recordingCell") as! RecordingCell
                return cell!
            }
            if indexPath.row != 0{
                selectButton.isEnabled = true
                let cell = self.tableView.dequeueReusableCell(withIdentifier: "videoCell") as! VideoCell
                cell.videoURL = videoURLS[indexPath.row - 1]
                cell.parent = self
                cell.setViews()
                cell.setString()
                cell.setDate()
                cell.setTitle()
                cell.setSize()
                cell.setJpg()
                return cell
            }
        }
        else{
            selectButton.isEnabled = true
            let cell = self.tableView.dequeueReusableCell(withIdentifier: "videoCell") as! VideoCell
            cell.videoURL = videoURLS[indexPath.row]
            cell.parent = self
            cell.setViews()
            cell.setString()
            cell.setDate()
            cell.setTitle()
            cell.setSize()
            cell.setJpg()
            return cell
        }
        
    }

Sorry, I didn't see it.


But there is a difference between the 2 versions in this part:


        if tableView.numberOfRows(inSection: 0) == (videoURLS.count + 1){ 
            if indexPath.row == 0{ 
                let cell = self.tableView.dequeueReusableCell(withIdentifier: "recordingCell") as! RecordingCell 
                return cell! 
            } ow you return cell!


Now you return cell!, before you returned cell.

But cell is no more optional, because of as!

Sorry, typo. My actual code doesn't have it. I was trying to simply return cell without defining it as RecordingCell, but I'm getting the error at the end of the function.

I think the compiler is not smart enough to see that the 2 test == 0 and later != 0 cover all cases.

Hence, in

if indexPath.row != 0 {

if it is not true, it looks for the else case, not seeing it was handled just above.


You should try this


          if tableView.numberOfRows(inSection: 0) == (videoURLS.count + 1){
               if indexPath.row == 0 {
                    let cell = self.tableView.dequeueReusableCell(withIdentifier: "recordingCell") as! RecordingCell
                    return cell
               } else {     // This instead of the following test
 //              if indexPath.row != 0 {
                    selectButton.isEnabled = true
                    let cell = self.tableView.dequeueReusableCell(withIdentifier: "videoCell") as! VideoCell
                    cell.videoURL = videoURLS[indexPath.row - 1]
                    cell.parent = self
                    cell.setViews()
                    cell.setString()
                    cell.setDate()
                    cell.setTitle()
                    cell.setSize()
                    cell.setJpg()
                    return cell
               }
          }

derp....yup....


OK, that fixes that, but how come it still doesn't see "RecordingCell"??

What do you mean "it does not see Recording cell" ? That you never reach thos portion of code ?


I would add some print to check:


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
      
        if videoURLS.count == 0 {
            print("video count is zero")
            selectButton.isEnabled = false
            let cell = tableView.dequeueReusableCell(withIdentifier: "emptyCell")
            return cell!
        }
             // So here, videoURLS.count >= 1
     print("number of rows", tableView.numberOfRows(inSection: 0))
     print("video count", videoURLS.count)
        if tableView.numberOfRows(inSection: 0) == (videoURLS.count + 1) {
            if indexPath.row == 0 {
                print("IndexPath row is zero")
                let cell = self.tableView.dequeueReusableCell(withIdentifier: "recordingCell") as! RecordingCell
                return cell
            } else {
             print("IndexPath row is", indexPath.row)
                    selectButton.isEnabled = true  
                    let cell = self.tableView.dequeueReusableCell(withIdentifier: "videoCell") as! VideoCell  
                    cell.videoURL = videoURLS[indexPath.row - 1]  
                    cell.parent = self  
                    cell.setViews()  
                    cell.setString()  
                    cell.setDate()  
                    cell.setTitle()  
                    cell.setSize()  
                    cell.setJpg()  
                    return cell  
               }  
     } else {
          print("number of rows is not count + 1")
     }


What do you get ?

What I mean is this:


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        if videoURLS.count == 0{
            selectButton.isEnabled = false
            let cell = tableView.dequeueReusableCell(withIdentifier: "emptyCell")
            return cell!
        }
            
        if tableView.numberOfRows(inSection: 0) == (videoURLS.count + 1){
            if indexPath.row == 0{
                let cell = self.tableView.dequeueReusableCell(withIdentifier: "recordingCell") as! RecordingCell
                return cell
            }
            else{
                selectButton.isEnabled = true
                let cell = self.tableView.dequeueReusableCell(withIdentifier: "videoCell") as! VideoCell
                cell.videoURL = videoURLS[indexPath.row - 1]
                cell.parent = self
                cell.setViews()
                cell.setString()
                cell.setDate()
                cell.setTitle()
                cell.setSize()
                cell.setJpg()
                return cell
            }
        }
        else{
            selectButton.isEnabled = true
            let cell = self.tableView.dequeueReusableCell(withIdentifier: "videoCell") as! VideoCell
            cell.videoURL = videoURLS[indexPath.row]
            cell.parent = self
            cell.setViews()
            cell.setString()
            cell.setDate()
            cell.setTitle()
            cell.setSize()
            cell.setJpg()
            return cell
        }        
    }


returns an error at line 11 stating Use of endeclared type 'RecordingCell'However 'RecordingCell' is written and targeted correctly! It's within the scope of the class that the function is in. Here's 'RecordingCell':


import UIKit

class RecordingCell: UITableViewCell {
        
    @IBOutlet var titleLabel: UILabel!
    var title : String = ""
        
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        title = titleLabel.text!        
        titleAnimation()        
    }
    
    func titleAnimation(){
        print ("starting the animation function")
        UIView.animate(withDuration: 1.5, delay: 1.5, options: .curveEaseInOut, animations: {
            
            self.titleLabel.text! = "Recording in Progress"
    
        }, completion: nil)
    
    
    }
}


In the Utitlies tab, it's target is set properly. I've even tried resetting the target.

What deos VideoCell looks like ? Is it declared differenttly ?

Have you checked the identifiers are correct ?

Did you resgister the cell :

func register(_ cellClass: AnyClass?, forCellReuseIdentifier identifier: String)

Prior to dequeueing any cells, call this method or the

register(_:forCellReuseIdentifier:)
method to tell the table view how to create new cells.



In an app where I had 2 types of cells, one for header (custom cell HeaderCell) and the basic one for other cells, I did the following


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: basicCell, for: indexPath)

        var cellForHeader = tableView.dequeueReusableCell(withIdentifier: headerCell, for: indexPath) as? HeaderCell
        if (cellForHeader == nil) {
            cellForHeader = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: HeaderCell) as? HeaderCell
        }

And I registered the nib for headerCell

Depending on the case, I return cell or cellForHeader.

Have you fixed all other errors in your project?

Have you tried Clean Build after fixing all other errors?


If you put some error code into your RecordingCell.swift, what do you get?