Swift 3 Breaks Cell For Row At Index Path

丶灬走出姿态 提交于 2019-12-12 01:27:08

问题


This code was from a now inactive tutorial that helped me load in data to a table view. Since the tutorial was written in Swift 2.0, I believe that this was changed in Swift 3. I know that the override function itself was changed, which I handled. But now, it brings me a Thread 1: EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP, subcode=0x0) error.

Update: I have tried multiple things including creating a custom class for the cell. I still either get the same error I listed above, or a Thread 1: Signal SIGABRT error on the first line of my App Delegate file. Creating a breakpoint hasn't helped me because I know where the error is coming from.

import UIKit
import Firebase
import FirebaseDatabase


struct postStruct {
    let title : String!
    let message : String!
}

class LoggedInController: UITableViewController {

    var posts = [postStruct]()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.delegate = self
        self.tableView.dataSource = self

        let databaseRef = FIRDatabase.database().reference()

        databaseRef.child("Posts").queryOrderedByKey().observe(.childAdded, with: {
            snapshot in

            let snapshotValue = snapshot.value as? NSDictionary
            let title = snapshotValue!["title"] as? String

            let message = snapshotValue!["message"] as? String

            self.posts.insert(postStruct(title: title, message: message), at: 0)
            self.tableView.reloadData()
        })

        post()
    }

    func post(){

        let title = "Title"
        let message = "Message"

        let post : [String : AnyObject] = ["title" : title as AnyObject,
                                           "message": message as AnyObject]

        let databaseRef = FIRDatabase.database().reference()

        databaseRef.child("Posts").childByAutoId().setValue(post)

    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return posts.count
    }

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

    let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell")

    let label1 = cell?.viewWithTag(1) as! UILabel
    label1.text = posts[indexPath.row].message

    let label2 = cell?.viewWithTag(2) as! UILabel
    label2.text = posts[indexPath.row].message

    return cell!
    }
}

Update 2: Here is the new code I used. It's not pretty and only gets the title.

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return posts.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")

    if cell == nil {
        cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
        cell?.textLabel?.text = posts[indexPath.row].title
        cell?.detailTextLabel?.text = posts[indexPath.row].message
        return cell!
    } else {
        let label1 = cell?.viewWithTag(1) as? UILabel
        label1?.text = posts[indexPath.row].title

        let label2 = cell?.viewWithTag(2) as? UILabel
        label2?.text = posts[indexPath.row].message
        return cell!
    }
}

回答1:


Using dequeueReusableCell, you are accessing cell which doesn't exists. To make your code work change the below line:

let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")

To

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



回答2:


Ok this code let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") produces an optional called cell that may or may not contain a a valid instance of UITableViewCell. Optionals in Swift are a way to safeguard against nil values, you can read more about optionals here: Optionals

On the first run when your table view wants to load its data it calls all the required methods of your UITableViewDataSource. The first run is a critical one because there aren't any instances of the UITableViewCell the table view can dequeue yet. To solve your problem you have to do something similar to the code below:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return posts.count
    }

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCell(withIdentifier: "cell")

    if cell == nil {
        cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
        cell?.textLabel?.text = "New value"
        cell?.detailTextLabel?.text = "New value"
        return cell!
    } else {
        cell?.textLabel?.text = "" //reset value
        cell?.detailTextLabel?.text = "" // resetValue
        cell?.textLabel?.text = "New value"
        cell?.detailTextLabel?.text = "New value"
        return cell!
    }
}

Code similar to the one above are usually used to programmatically add an instance of UITableViewCell. However, if you used interface builder to add a prototype cell use the let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) method to dequeue your cells in which case it does not return an optional and you do not need to do all the if / else blocks. Something else I wanted to mention about your code is finding sub views buy their ID will not produce a very object oriented code and that maybe the source of your errors where the compiler can not find the sub views. The better way would be to use one of the built in instances of UITableViewCell such as .default or alliteratively you could subclass the said class and make your very own custom cells.

Hope this helped!




回答3:


Try this

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
 {
    let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!

    let label1 = cell.viewWithTag(1) as! UILabel
    label1.text = posts[indexPath.row].message

    let label2 = cell.viewWithTag(2) as! UILabel
    label2.text = posts[indexPath.row].message

    return cell
}

Edited

Make Sure you did these things

UITableViewController

In viewDidLoad()

self.tableView.register(UITableViewCell.self,     forCellReuseIdentifier:"catCell" )
let catNib : UINib = UINib.init(nibName: "TableViewCategoryCell",  bundle: nil)
self.tableView.register(catNib, forCellReuseIdentifier: "TableViewCategoryCell")

In cellForRowAt indexPath

let cell : OPM_AlarmTableViewCategoryCell = tableView.dequeueReusableCell(withIdentifier:"OPM_AlarmTableViewCategoryCell" ) as! OPM_AlarmTableViewCategoryCell!
cell.categoryLabel?.text = "Some Text"
return cell

UITableviewCell.XIB Hope u did these things

UITableviewCell Make sure the dot appears so that the @IBOutlet is connected with the xib label



来源:https://stackoverflow.com/questions/40797508/swift-3-breaks-cell-for-row-at-index-path

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!