Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

iOS Build a Self-Destructing Message iPhone App Retrieving and Viewing Data from Parse.com Retrieving Data from Parse.com

Dee Greene
Dee Greene
8,508 Points

Display unread messages

I would like to update the inbox badge to display the number of unread messages (my messages don't self destruct, app is similar to iOS messages). When the user clicks on a messages and goes back to the inbox tab the badge should be updated. Also, I would like to mark the background color of the unread cells differently than the cells of read...that way the user knows what has been read and what hasn't. I have some working code but right now I am getting:

"Warning: A long-running operation is being executed on the main thread. 
 Break on warnBlockingOperationOnMainThread() to debug."
PFQuery *query = [PFQuery queryWithClassName:@"Messages"];
        [query whereKey:@"recipientIds" equalTo:[[PFUser currentUser] objectId]];
        [query orderByDescending:@"createdAt"];
        [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
            if (error) {
                NSLog(@"Error: %@ %@", error, [error userInfo]);
            } else {
                // messages were found!
                self.messages = objects;

                //find unread messages
                [query whereKey:@"readBy" notEqualTo:[[PFUser currentUser] objectId]];
                self.unreadMessages = [query findObjects];

                // set badge # to number of msgs
                if (self.unreadMessages.count > 0) {

                    [[self navigationController] tabBarItem].badgeValue = [NSString stringWithFormat:@"%lu", (unsigned long)self.unreadMessages.count];
                }

                [self.tableView reloadData];

4 Answers

Dee Greene
Dee Greene
8,508 Points

I have the code now working for displaying the correct badge number

PFQuery *query = [PFQuery queryWithClassName:@"Messages"];
        [query whereKey:@"recipientIds" equalTo:[[PFUser currentUser] objectId]];
        [query orderByDescending:@"createdAt"];
        [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
            if (error) {
                NSLog(@"Error: %@ %@", error, [error userInfo]);
            } else {
                // messages were found!
                self.messages = objects;

                //find unread messages
                [query whereKey:@"readBy" notEqualTo:[[PFUser currentUser] objectId]];

                //start stackoverflow code
                [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
                {
                    if (!error)
                    {
                        self.unreadMessages = [NSMutableArray arrayWithArray:objects];
                        //NSLog(@"unread: %@", self.unreadMessages);
                        // set badge # to number of msgs
                        if (self.unreadMessages.count > 0)
                        {
                            [[self navigationController] tabBarItem].badgeValue = [NSString stringWithFormat:@"%lu", (unsigned long)self.unreadMessages.count];
                        }
                        [self.tableView reloadData];

however, my code for updating the cell is not

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

    PFObject *message = [self.messages objectAtIndex:indexPath.row];
    cell.textLabel.text = [message objectForKey:@"senderEmail"];

    if ([self.unreadMessages containsObject:message]) {
        // color background gray, bold the font
    }else{
       // leave cell alone
    }
Ra’Shii Henry
Ra’Shii Henry
16,433 Points

when are you calling your query? in the viewDidLoad?

Dee Greene
Dee Greene
8,508 Points

viewWillAppear

Ra’Shii Henry
Ra’Shii Henry
16,433 Points

Wassup bro,

I believe your problem is where you're finding the unread message. You're already running one query and since the query is executed there won't be an error so it moves on and tries to re-query the found objects in the first block.

THATS THE PROBLEM FOR THE ERROR MESSAGE. running two or more queries simultaneously before the first query can finish.

try calling it before reloadData and outside of the else condition. See what happens.

OR

since youre using notEqualTo, try using whereKey: containsString: if 'readBy' containsString:objectID then you know those are all read. Subtract those from the total count(of your readyBy array) to get your unread messages.

Ra’Shii Henry
Ra’Shii Henry
16,433 Points

Set a breakpoint on the PFObject *message line and step through and see if the object is nil. The key for the message object may be nil.

Dee Greene
Dee Greene
8,508 Points

I made a "readBy" field and updated cellForRowAtIndexPath to

if ([[message objectForKey:@"readBy"] containsObject:[[PFUser currentUser] objectId]]) {
            // read message found
            cell.textLabel.font = [UIFont fontWithName:@"Helvetica-Bold" size:17.0f];
            cell.textLabel.textColor = [UIColor blackColor];
        }else{
            // unread message found
            cell.textLabel.textColor = [UIColor redColor];
            cell.textLabel.font = [UIFont fontWithName:@"Helvetica-Bold" size:17.0f];
        }
Ra’Shii Henry
Ra’Shii Henry
16,433 Points

okay you used containsObject. It was pretty much the same thing i was suggesting you did with the PFQuery. Its good you found a solution.