1

I've been on stack for a while now but never needed to ask a question as I've always found the answers after some searching, but now I'm stuck for real. I've been searching around and going through some trial and error for an answer and I keeping getting the same error. I'm basically making a profile page with a tableView on the bottom half of the screen. The top half is loading fine filling in the current user's information. All connections to the view controller and cell view controller seem good. The table view, however, will appear with no data and crash while loading with the fatal error:

unexpectedly found nil while unwrapping an optional value.

I also believe the cellForRowAtIndexPath is not being called at all because "test" is not printing to the logs.

I'm using the latest versions of Swift and Parse.

I'm relatively new to swift so I'll go ahead and post my entire code here and any help at all is appreciated.

import UIKit
import Parse
import ParseUI

class profileViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {


@IBOutlet var tableView: UITableView!
@IBOutlet var profilePic: UIImageView!
@IBOutlet var userName: UILabel!
@IBOutlet var userBio: UILabel!
var image: PFFile!
var username = String()
var userbio = String()
var content = [String]()


@IBAction func logout(sender: AnyObject) {
    PFUser.logOut()
    let Login = storyboard?.instantiateViewControllerWithIdentifier("ViewController")
    self.presentViewController(Login!, animated: true, completion: nil)

}

override func viewDidLoad() {
    super.viewDidLoad()


    profilePic.layer.borderWidth = 1
    profilePic.layer.masksToBounds = false
    profilePic.layer.borderColor = UIColor.blackColor().CGColor
    profilePic.layer.cornerRadius = profilePic.frame.height/2
    profilePic.clipsToBounds = true


    tableView.delegate = self
    tableView.dataSource = self


    self.tableView.rowHeight = 80


    self.hideKeyboardWhenTappedAround()

    if let nameQuery = PFUser.currentUser()!["name"] as? String {
        username = nameQuery
    }

    if PFUser.currentUser()!["bio"] != nil {
    if let bioQuery = PFUser.currentUser()!["bio"] as? String {
        userbio = bioQuery
    }
    }

    if PFUser.currentUser()!["icon"] != nil {
    if let iconQuery = PFUser.currentUser()!["icon"] as? PFFile {
        image = iconQuery
    }
    }



    self.userName.text = username
    self.userBio.text = userbio

    if image != nil {
    self.image.getDataInBackgroundWithBlock { (data, error) -> Void in


        if let downIcon = UIImage(data: data!) {


            self.profilePic.image = downIcon

        }
        }

    }


    // Do any additional setup after loading the view.

    var postsQuery = PFQuery(className: "Posts")

    postsQuery.whereKey("username", equalTo: username)

    postsQuery.findObjectsInBackgroundWithBlock( { (posts, error) -> Void in

        if error == nil {

            if let objects = posts {
                self.content.removeAll(keepCapacity: true)

                for object in objects {
                    if object["postText"] != nil {
                        self.content.append(object["postText"] as! String)
                    }
                    self.tableView.reloadData()
                }
            }
        }

    })

}




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


func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Potentially incomplete method implementation.
    // Return the number of sections.
    return 1
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete method implementation.
    // Return the number of rows in the section.
    print(content.count)
    return content.count
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let profCell = self.tableView.dequeueReusableCellWithIdentifier("profCell", forIndexPath: indexPath) as! profTableViewCell

    print("test")

    profCell.userPic.layer.borderWidth = 1
    profCell.userPic.layer.masksToBounds = false
    profCell.userPic.layer.borderColor = UIColor.blackColor().CGColor
    profCell.userPic.layer.cornerRadius = profCell.userPic.frame.height/2
    profCell.userPic.clipsToBounds = true


    profCell.userPic.image = self.profilePic.image
    profCell.name.text = self.username




    profCell.content.text = content[indexPath.row]



    return profCell
}

}
Nirav D
  • 71,513
  • 12
  • 161
  • 183
boppa
  • 149
  • 3
  • 15
  • You don't seem to have registered your custom UITableViewCell class in the UIViewController code? – Woodstock Sep 02 '16 at 15:01
  • update screenshot along if possible , to prevent such error use if let mvar = yourvariable {} or make sure u tied tableview outlet correctly and delegate and datasource – Shobhakar Tiwari Sep 02 '16 at 15:01
  • What line does it crash on? – acorc Sep 02 '16 at 15:03
  • @acorc it must be at the dequeue, which is using a forced unwrap. Probably just needs to: self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "someCustomCell") – Woodstock Sep 02 '16 at 15:05
  • 1
    @Woodstock assuming he didn't register a prototype cell w/ that identifier in the storyboard (he has outlets at the top) I'd agree. This is why I stopped using Storyboards, too much obscurity makes it difficult to track down issues. – acorc Sep 02 '16 at 15:09
  • @acorc agreed. I don't use SB either. – Woodstock Sep 02 '16 at 15:39

3 Answers3

6

I let it sit for a few days and I came back to realize a very dumb mistake I made. I working with around 15 view controllers right now and realized I had a duplicate of the one I posted above with the same name. I now understand why you say working with storyboards is very sticky. Though, I did not need it, I appreciate the help and I can say I learned a few things.

boppa
  • 149
  • 3
  • 15
0

You probably need to register the class you are using for the custom UITableViewCell:

self.tableView.registerClass(profTableViewCell.self, forCellReuseIdentifier: "profCell") 

Unless you're using prototyped cells in IB, this registration isn't done automatically for you.

As such when you call the dequeue method (with the ! forced unwrap) you're going to have issues. The dequeueReusableCellWithIdentifier:forIndexPath: asserts if you didn't register a class or nib for the identifier. when you register a class, this always returns a cell.

The older (dequeueReusableCellWithIdentifier:) version returns nil in that case, and you can then create your own cell.

You should use a ? during the as cast to avoid the crash, although you'll get no cells!

One other reminder, you should always use capitals for a class name, ProfTableViewCell not profTableViewCell, it's just good pratice.

Much more information here in the top answer by iOS genius Rob Mayoff: Assertion failure in dequeueReusableCellWithIdentifier:forIndexPath:

Community
  • 1
  • 1
Woodstock
  • 22,184
  • 15
  • 80
  • 118
  • Thanks the prompt response. I figured the problem was with exactly that line. I was using a prototype cell with the correct reuse identifier on the storyboard. However, as soon as I get back to my computer, I will try this method as well to see if that works for my case and post an update – boppa Sep 02 '16 at 15:51
  • If you're using a prototype cell in the storyboard then you shouldn't register a class in code. – dan Sep 02 '16 at 15:54
0

You have to create a simple NSObject Class with image, username and userbio as optional values. Then you have to declare in your profileviewcontroller a var like this:

var allProfiles = [yourNSObjectClass]()

In your cellForRowAtIndexPath add:

let profile = yourNSObjectClass()
profile = allProfiles[indexPath.row]

cell.username.text = profile.username

And go on.

Use also this:

   dispatch_async(dispatch_get_main_queue(), {
                self.tableView.reloadData()
            })

instead of this:

self.tableView.reloadData()
Carlo
  • 813
  • 1
  • 15
  • 34
  • Interesting... could be! Does findObjectsInBackgroundWithBlock, always run on its own background thread? – Woodstock Sep 02 '16 at 15:25
  • In my little experience yes. It is a good way to solve problem like this. – Carlo Sep 02 '16 at 15:29
  • I tried this fix earlier and still got the same error. Will try it again if registering the class still does not properly compile – boppa Sep 02 '16 at 15:53