adams.s adams.s - 1 year ago 225
Swift Question

Retrieving firebase data of a tableview cell to a view controller's label

I have like a social app with a sort of newsfeed. if u click on the users name from a post in the newsfeed, you will go to his profile. Now i can't retrieve the data from that specific cell/post to the other viewController.
so i have to display the user's profile, with he's username, etc. but that doesn't work?

i have a Post model:

class Post {
private var _postDescription: String!
private var _profileImageURL: String?
private var _likes: Int!
private var _username: String!
private var _postKey: String!
private var _timeStamp: String!
private var _postRef: Firebase!

var postDescription: String? {
return _postDescription

var likes: Int {
return _likes

var username: String {
return _username

var postKey: String {
return _postKey

var profileImageURL: String? {
return _profileImageURL

init(description: String, username: String, profileImageURL: String?) {
self._postDescription = description
self._username = username
self._profileImageURL = profileImageURL

init(postKey: String, dictionary: Dictionary<String, AnyObject>) {
self._postKey = postKey

if let likes = dictionary["likes"] as? Int {
self._likes = likes

if let desc = dictionary ["description"] as? String {
self._postDescription = desc

if let imgUrl = dictionary["profileImg"] as? String {
self._profileImageURL = imgUrl

if let user = dictionary ["username"] as? String {
self._username = user
} else {
self._username = ""

self._postRef = DataService.ds.REF_POST.childByAppendingPath(self._postKey)


this is my profileVC:

class ProfileVC: UIViewController {

@IBOutlet weak var username: UILabel!

var post: Post?

override func viewDidLoad() {

username.text = post.username // gives me a nil error.

and i use a TapGestureRecognizer in my tableViewCell to perform the segue.
in my cellForRowAtIndexPath:

let profileLblTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(NewsVC.goToProfileScreen(_:)))
profileLblTapRecognizer.numberOfTapsRequired = 1
profileLblTapRecognizer.delegate = self

cell.usernameLabel.tag = indexPath.row
cell.usernameLabel.userInteractionEnabled = true

and the goToProfileScreen function:

func goToProfileScreen(gesture: UITapGestureRecognizer) {
self.performSegueWithIdentifier("ProfileScreen", sender: self)


this is my datamodel on firebase:
enter image description here


i tried this instead:

let profileLblTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(NewsVC.prepareForSegue(_:sender:)))

with this function:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ProfileScreen" {
if let cell = sender as? NewsCell, row = tableView.indexPathForCell(cell)?.row, vc = segue.destinationViewController as? ProfileVC { = posts[row]




but that gave me an error on appDelegate: Thread 1: EXC_BAD_ACCESS(code=1, address = 0x1)

Answer Source

I've added this as an answer rather than a comment so that I can add and format some code examples.

When you call performSegueWithIdentifier, a NEW instance of the view controller identified by that segue is created, so all of its properties will be their defaults.

You have two ways of instantiating this view controller and setting properties before it loads. The first is the prepareForSegue option, in your case it may look something like this:

override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
    if (segue.identifier == "ProfileScreen") {
        let vc = segue.destinationViewController as! ProfileVC = post

Another option is to create and present the view controller yourself, this example uses a storyboardID

let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = mainStoryboard.instantiateViewControllerWithIdentifier("profileVC") as! ProfileVC = post

presentViewController(vc, animated: false, completion: nil)


I'm not sure why you are adding a tap gesture recogniser to this, you could just use didSelectRowAtIndexPath, have a look at this other question and answer

you could have a property on your table view controller called selectedItem or something similar. and then in didSelectRowAtIndexPath set selectedItem to the item at the current index. Then in prepare for segue you would just do = selectedItem

Update Two:

After the op sharing their code privately, I noticed that the issue is that the user is using tapGestureRecogniser in the tableView. I added some code into the called function to get the row in which contained the tapped view, once I had the indexPath it was then easy to store it in a temporary property and retreive later in the prepareForSegue method, details below

// temp property
var selectedPost:Post?

// function called on tap
func viewProfile(sender:UITapGestureRecognizer) {

    if (sender.state == UIGestureRecognizerState.Ended) {
        let point = sender.locationInView(self.tableView)
        if let indexPath = self.tableView.indexPathForRowAtPoint(point) {
            selectedPost = self.posts[indexPath.row]
            performSegueWithIdentifier("ProfileScreen", sender: self)

// Prepare for segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    if (segue.identifier == "ProfileScreen") {
        let vc = segue.destinationViewController as! ProfileVC
        if let post = selectedPost {
   = post
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download