1

I am building an iOS app in swift. I have a UIViewController that displays a few labels and fields and I would like to add a tableview. I'm a total swift noob, but after much googling, I've gotten everything integrated and "working" properly. However, I am encountering a "fatal error: unexpectedly found nil while unwrapping an Optional value" when I use dequeueReusableCellWithIdentifier. My cell is a custom class with just two IBOutlets, detailKey and detailValue. Any suggestions?

import UIKit

class ContactViewController: UIViewController, UITableViewDataSource,     UITableViewDelegate {

// MARK:Properties
var contact : Contact?
var params : [Detail]?

@IBOutlet weak var keywords: UILabel!
@IBOutlet weak var name: UILabel!
@IBOutlet weak var contactDetails: UITableView!

// for use in params array
struct Detail {
    var key : String,
        value : String
}

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    contactDetails.dataSource = self
    contactDetails.delegate = self

    if (self.contact != nil) {
        // set default value for params array since optional
        self.params = []

        // make keywords string
        var count : Int = 0
        var keywordString : String = ""

        while count < contact!.keywords.count {
            keywordString += contact!.keywords[count].description

            if count + 1 < contact!.keywords.count {
                keywordString += ", "
            }

            count += 1
        }

        // compile details for tableview
        if (!self.contact!.company.isEmpty) { self.params! += [Detail(key: "Company", value: self.contact!.company)] } // company
        if (!self.contact!.phone1.isEmpty) {
            self.params! += [Detail(key: self.contact!.phone_label1.isEmpty ? "Phone 1" : self.contact!.phone_label1, value: self.contact!.phone1)]
        }
        if (!self.contact!.phone2.isEmpty) {
            self.params! += [Detail(key: self.contact!.phone_label2.isEmpty ? "Phone 2" : self.contact!.phone_label2, value: self.contact!.phone2)]
        }
        if (!self.contact!.email1.isEmpty) {
            self.params! += [Detail(key: self.contact!.email_label1.isEmpty ? "Email 1" : self.contact!.email_label1, value: self.contact!.email1)]
        }
        if (!self.contact!.email2.isEmpty) {
            self.params! += [Detail(key: self.contact!.email_label2.isEmpty ? self.contact!.email_label2 : "Email 2", value: self.contact!.email2)]
        }
        if (!self.contact!.street.isEmpty) { self.params! += [Detail(key: "Address", value: self.contact!.address)] } // address (condition checks for street)
        if (!self.contact!.dob.isEmpty) { self.params! += [Detail(key: "Birthday", value: self.contact!.dob)] } // dob
        if (!self.contact!.social.isEmpty) { self.params! += [Detail(key: "Social Security Number", value: self.contact!.social)] } // social

        self.name.text = contact!.name
        self.keywords.text = keywordString
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

// table view stuffs
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.params!.count ?? 0
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    print("going")
    let cell = tableView.dequeueReusableCellWithIdentifier("contactDetail") as! ContactDetailTableViewCell
    let param = self.params![indexPath.row]

    print(param.key + ": " + param.value)

    cell.detailKey.text = param.key
    cell.detailValue.text = param.value

    return cell
}

enter image description here

Nick Winner
  • 222
  • 1
  • 11
  • make sure your `Reuse Cell Identifier` is correct. Also try n replace *tableview* to *contactDetails* – Dravidian Aug 28 '16 at 21:03
  • @Dravidian Thank you for your response! as far as I can tell, my Reuse Cell Identifier is correct, the attached screenshot proves that I think. In place of tableview, I tried both contactDetails and self.contactDetails to no avail – Nick Winner Aug 28 '16 at 21:08
  • Are you sure your IBOutlets are connected properly? – Pranav Wadhwa Aug 28 '16 at 21:08
  • @penatheboss Thank you for your response, I just deleted and reconnected all IBOutlets and I'm still getting the error. I've remade the table/cell class twice today and I can't get rid of it – Nick Winner Aug 28 '16 at 21:12
  • All that screenshot proves is that your cell is of custom class *ContactDetailTableViewCell*.. – Dravidian Aug 28 '16 at 21:29
  • @Dravidian how do I set the Reuse Cell Identifier? I thought that was set in the Identifier field? – Nick Winner Aug 28 '16 at 21:30

2 Answers2

3

Make sure your IBOutlets are connected properly. Drag from your view to the connection in your code.

Pranav Wadhwa
  • 7,202
  • 6
  • 31
  • 53
  • I have done so and I'm still getting the error. I built the layout in Interface Builder and dragged the tableview and both name label and keyword label into my view controller. – Nick Winner Aug 28 '16 at 22:10
  • Sometimes the connections break... There should be circles on the left of the outlet. If they are empty, that means the connection is broken. If so, reconnect it – Pranav Wadhwa Aug 28 '16 at 22:28
  • Thank you! I actually wound up fixing it with Dravidians answer. – Nick Winner Aug 28 '16 at 22:30
3

To set your cell identifier Select your cell then you will see Identifier field in Attributes Inspector, set your reuse identifier there... That's about it..

Also try adding :-

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

and replace

 let cell = tableView.dequeueReusableCellWithIdentifier("contactDetail") as! ContactDetailTableViewCell

to

let cell = tableView.dequeueReusableCellWithIdentifier("contactDetail", forIndexPath: indexPath) as! ContactDetailTableViewCell

EXPLANATION

CMD+CLICK on the function Name : dequeueReusableCellWithIdentifier-- you will be directed to its documentation ..

public func dequeueReusableCellWithIdentifier(identifier: String) -> UITableViewCell? // Used by the delegate to acquire an already allocated cell, in lieu of allocating a new one.
@available(iOS 6.0, *)
public func dequeueReusableCellWithIdentifier(identifier: String, forIndexPath indexPath: NSIndexPath) -> UITableViewCell // newer dequeue method guarantees a cell is returned and resized properly, assuming identifier is registered
  • dequeueReusableCellWithIdentifier(identifier: String, forIndexPath indexPath: NSIndexPath) guarantees you a cell..

Maybe these links are helpful :-

Fatal error: unexpectedly found nil while unwrapping an Optional values

https://stackoverflow.com/a/25569704/6297658

Community
  • 1
  • 1
Dravidian
  • 9,725
  • 2
  • 30
  • 67
  • So I added the numberOfSections function in, nothing happened. When I change the dequeueReusableCellWithIdentifier function however, the error changes: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier contactDetail - must register a nib or a class for the identifier or connect a prototype cell in a storyboard' – Nick Winner Aug 28 '16 at 22:09
  • You, sir, are beautiful. And I am an idiot. I set the Identifier in the Identity Inspector but not in the Attribute Inspector. 2 days of hair pulling for this... thank you! – Nick Winner Aug 28 '16 at 22:29