Reputation:
I have a tableView where I'd like to display my comments for example how instagram and many other social networks do. 3 comments below the post, here's an image to explain:
as you can see from that image, at the top you have the post, then the caption, and finally the 3 latest comments.
I have added a commentng system to my app, and I can view all the comments when I click on the comment icon and I get redirected to the new VC.
I also have a UUID for each post for when I'm adding the caption, So I think that could help in some way for connecting the comments to the post!
But now I'm looking to achieve this.
So far I have added 3 UIlabels in my storyboard below my post, then I have made a collection outlet for those labels. Now in my table view I have a query for getting the latest 3 comments :
var commentUsername = [String]()
var commentArray = [String]()
let Commentquery = PFQuery(className: "Comments")
Commentquery.whereKey("toPost", containedIn: self.uuidArray)
Commentquery.addDescendingOrder("createdAt")
Commentquery.limit = 3
Commentquery.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
self.commentUsername.removeAll(keepCapacity: false)
self.commentArray.removeAll(keepCapacity: false)
for object in objects! {
self.commentArray.append(object.objectForKey("comment") as! String)
self.commentUsername.append(object.objectForKey("username") as! String)
}
tableView.reloadData
}
})
And then here is how I display them in my CellForRowAtIndexPath:
var counter = (indexPath.row * 3)
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! NewsFeedTableViewCell
for comments in cell.threeComments{
comments.text = commentArray[counter++]
comments.sizeToFit()
}
It's on that line "comments.text = commentArray[counter++]" that I'm getting Array index out of range.
I'm guessing that I am receiving this error because its either return nil because there's no comments for that photo or there's not atleast 3 comments to fill the UILabels in...And that's what I have had difficulty with for a while now, If anyone knows how to fix or the correct possible "optional" query or something that would be great!!
For any further explanation please just comment below.
Best regards & thanks in advance!
Full code :
var usernameArray = [String]()
var profilePicture = [PFFile]()
var dateArray = [NSDate?]()
var postArray = [PFFile]()
var titleArray = [String]()
var uuidArray = [String]()
var followArray = [String]()
var commentUsername = [String]()
var commentArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
loadPosts()
}
func loadPosts() {
let followQuery = PFQuery(className: "Follows")
followQuery.whereKey("follower", equalTo: PFUser.currentUser()!.username!)
followQuery.findObjectsInBackgroundWithBlock ({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
self.followArray.removeAll(keepCapacity: false)
for object in objects! {
self.followArray.append(object.valueForKey("following") as! String)
}
self.followArray.append(PFUser.currentUser()!.username!)
let query = PFQuery(className: "Posts")
query.whereKey("username", containedIn: self.followArray)
query.limit = self.page
query.addDescendingOrder("createdAt")
query.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
self.usernameArray.removeAll(keepCapacity: false)
self.profilePicture.removeAll(keepCapacity: false)
self.dateArray.removeAll(keepCapacity: false)
self.postArray.removeAll(keepCapacity: false)
self.titleArray.removeAll(keepCapacity: false)
self.uuidArray.removeAll(keepCapacity: false)
for object in objects! {
self.usernameArray.append(object.valueForKey("username") as! String)
self.profilePicture.append(object.valueForKey("profilePicture") as! PFFile)
self.dateArray.append(object.createdAt)
self.postArray.append(object.valueForKey("image") as! PFFile)
self.titleArray.append(object.valueForKey("caption") as! String)
self.uuidArray.append(object.valueForKey("uuid") as! String)
}
let Commentquery = PFQuery(className: "Comments")
Commentquery.whereKey("toPost", containedIn: self.uuidArray)
Commentquery.addDescendingOrder("createdAt")
Commentquery.limit = 3
Commentquery.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
self.commentUsername.removeAll(keepCapacity: false)
self.commentArray.removeAll(keepCapacity: false)
for object in objects! {
self.commentArray.append(object.objectForKey("comment") as! String)
self.commentUsername.append(object.objectForKey("username") as! String)
}
self.tableView.reloadData()
}else {
print(error?.localizedDescription)
}
})
} else {
print(error!.localizedDescription)
}
})
} else {
print(error!.localizedDescription)
}
})
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return uuidArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var counter = (indexPath.row * 3)
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! NewsFeedTableViewCell
for comments in cell.threeComments{
comments.text = commentArray[counter++]
comments.sizeToFit()
}
}
}
Upvotes: 0
Views: 200
Reputation: 5554
@Jack - I think the solution is going to be very similar to your other question https://stackoverflow.com/questions/35854857/how-to-order-2-tableview-sections/35866457?noredirect=1#comment59402360_35866457 and you should look at storing the username & comment text in a struct, and loading the query results into that.
If everything is loaded into an array called comments
, then you still have a choice - either have a single label showing all three lines (set number of lines = 3 in storyboard), or have three labels
// single label
myLabel.text = ""
for comment in comments
{
myLabel.text += comment.text + "\n"
}
// multiple labels approach, assuming labels have tag value 100, 101, 102
for index in 0..<comments.count
{
let label = cell.contentView.viewWithTag(100 + index) as! UILabel
label.text = comments[index]
}
** updated - cell.contentView.viewWithTag **
I have used tag values starting at 100 rather than 0, to avoid any accidental matches with default values
Here's how you set the tag
value. In this example, I have two custom cells, and the yellow cell has three labels. If you select each label in turn, and set the Tag
attribute as shown, then every instance of the cell that is created will have those three labels with the same tags - but you only search within the context of an individual cell, so it doesn't matter about the other instances.
Upvotes: 0
Reputation: 10113
inside the tableview function (CellForRowAtIndexPath) indexPath.row gives current cell index number no need to iterate using a loop, if you need 3 cells you have to set it in
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return commentArray.count // you can set static number 3 here, instead of set 'commentArray.count'
}
.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! NewsFeedTableViewCell
comments.text = commentArray[indexPath.row]
comments.sizeToFit()
}
you can change your loop like this
for (index, comments) in cell.threeComments {
comments.text = commentArray[index]
comments.sizeToFit()
}
Upvotes: 2
Reputation: 7756
This design needs to be improved, (see comment) but to avoid the crash you could simply do:
for comments in cell.threeComments{
if commentsArray.count < counter {
comments.text = commentArray[counter]
comments.sizeToFit()
}
counter += 1
}
FYI, I removed the counter++ as unary operators are being removed in Swift 3.0
Upvotes: 0