Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS Build a Self-Destructing Message iPhone App Capturing Photo and Video Using UIImagePickerController Uploading the File and Message

Jonathan Fernandez
Jonathan Fernandez
8,325 Points

Showing Recipient Usernames in Parse Dashboard? (Self-Destructing Message App)

Just wanted to know if anyone knew how to get recipient usernames to also show in Parse Dashboard. In the video only the recipients ID was shown.

Is it simple or will I have to go through the process of PFQuerry to get user IDs or do something like helper methods to grab cell data and give me selected user username? I may be overthinking this.

<p>
- (void)uploadMessage {
    NSData *fileData;
    NSString *fileName;
    NSString *fileType;

    // Check if image or video
    if (self.image != nil) {
        // If image, shirnk it
        UIImage *newImage = [self resizeImage:self.image toWidth:320.0f andHeight:480.0f];
        fileData = UIImagePNGRepresentation(newImage); //PNG is safer cause PNGs can hold the same data as JPEGs but JPEGs can't hold the same data as PNGs
        fileName = @"image.png";
        fileType = @"image";



    } else {
        fileData = [NSData dataWithContentsOfFile:self.videoFilePath];
        fileName = @"video.mov";
        fileType = @"video";
    }

    // Upload the file itself
    PFFile *file = [PFFile fileWithName:fileName data:fileData];
    [file saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
        if (error) {
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"An error occured!" message:@"Please try sending your message again.!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alertView show];
        } else {
            // Upload message details
            PFObject *message = [PFObject objectWithClassName:@"Messages"];
            [message setObject:file forKey:@"file"];
            [message setObject:fileType forKey:@"fileType"];
            [message setObject:self.recipients forKey:@"recipientsIds"];
            [message setObject:/* [What do I add here??] */ forKey:@"recipientsUsername"]
            [message setObject:[[PFUser currentUser] objectId] forKey:@"senderId"];
            [message setObject:[[PFUser currentUser] username] forKey:@"senderName"];
            [message saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
                if (error) {
                    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"An error occured!" message:@"Please try sending your message again.!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                    [alertView show];
                } else {
                    // Everything was successful!
                    [self reset];

                }
            }];
        }
    }];

}
</p>

Any feedback would be greatly appreciated. : )

5 Answers

Stone Preston
Stone Preston
42,016 Points

can you post your didSelectRowAtIndexPath method? you could just add another array property called recipientUsernames and add the selected users username to that array and then in the upload message method just save that field in addition to the one that stores recipient ids:

- (void)uploadMessage {
 // ...
            // Upload message details
            PFObject *message = [PFObject objectWithClassName:@"Messages"];
            [message setObject:file forKey:@"file"];
            [message setObject:fileType forKey:@"fileType"];
            [message setObject:self.recipients forKey:@"recipientsIds"];
            [message setObject:self.recipientUsernames forKey:@"recipientUsernames"]
            [message setObject:[[PFUser currentUser] objectId] forKey:@"senderId"];
            [message setObject:[[PFUser currentUser] username] forKey:@"senderName"];
            [message saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
                if (error) {
                    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"An error occured!" message:@"Please try sending your message again.!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                    [alertView show];
                } else {
                    // Everything was successful!
                    [self reset];

                }
            }];
        }
    }];

//...

}
Jonathan Fernandez
Jonathan Fernandez
8,325 Points

Omg such genius!! Thank you so much for this answer.

Here is my new code below now and I have checked Parse and everything seems to be showing up nicely..

<p>
// .h
@property (strong, nonatomic) NSMutableArray *recipientsUsername; // New code added.

// .m
// ...
// didSelectRowAtIndexPath shown below
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [self.tableView deselectRowAtIndexPath:indexPath animated:NO];
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    PFUser *user = [self.friends objectAtIndex:indexPath.row];
    self.recipientsUsername = user.username; // new code added + Warning: Incompatible pointer types assigning to "NSMutableArray" from "NSString"

    if (cell.accessoryType == UITableViewCellAccessoryNone) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        [self.recipients addObject:user.objectId];
    } else {
        cell.accessoryType = UITableViewCellAccessoryNone;
        [self.recipients removeObject:user.objectId];
    }
}

// ...


// ...
//  Upload message details 
            PFObject *message = [PFObject objectWithClassName:@"Messages"];
            [message setObject:file forKey:@"file"];
            [message setObject:fileType forKey:@"fileType"];
            [message setObject:self.recipients forKey:@"recipientsIds"];
            [message setObject:self.recipientsUsername forKey:@"recipientsUsername"]; // New code added.
            [message setObject:[[PFUser currentUser] objectId] forKey:@"senderId"];
            [message setObject:[[PFUser currentUser] username] forKey:@"senderName"];
            [message saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
                if (error) {
                    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"An error occured!" message:@"Please try sending your message again.!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                    [alertView show];
                } else {
                    // Everything was successful!
                    [self reset];

                }
            }];
        }
    }];

}

// ...

</p>

Hope I'm coding this the right way. Let me know if there is a better way I can code this cause I'm a bit worried that:

<p>
 self.recipientsUsername = user.username; 
</p>

is marked as Incompatible pointer types assigning to "NSMutableArray" from "NSString" in Xcode. Thanks again for your feedback. : )

Stone Preston
Stone Preston
42,016 Points

ah sorry. you need to use the add object method like so inside didSelectRowAtINdexPath:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [self.tableView deselectRowAtIndexPath:indexPath animated:NO];
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    PFUser *user = [self.friends objectAtIndex:indexPath.row];


    if (cell.accessoryType == UITableViewCellAccessoryNone) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        [self.recipients addObject:user.objectId];
        //add the users name to the usernames array
        [self.recipientUsernames addObject:user.username];
    } else {
        cell.accessoryType = UITableViewCellAccessoryNone;
        [self.recipients removeObject:user.objectId];
    }
}

I would change your array name to recipientUsernames so its more explicit that it stores more than one username instead of just recipientsUsername

Jonathan Fernandez
Jonathan Fernandez
8,325 Points

Thanks for the reply. I had changed the code and no warning signs seem to be showing up. However the app now crashes with this new code. I have run an execution point and it tells me that the code breaks at the upload message detail. Shown below is my new code:

<p>
// .m
// ...
// didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [self.tableView deselectRowAtIndexPath:indexPath animated:NO];
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    PFUser *user = [self.friends objectAtIndex:indexPath.row];

 // self.recipientUsernames = user.username; //Old code deleted/commented out. (This was where the warning sign was)

    if (cell.accessoryType == UITableViewCellAccessoryNone) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        [self.recipients addObject:user.objectId];
        [self.recipientUsernames addObject:user.username]; // New Code Added
    } else {
        cell.accessoryType = UITableViewCellAccessoryNone;
        [self.recipients removeObject:user.objectId];
        [self.recipientUsernames removeObject:user.username]; // New Code Added
    }
}

// ...

// ...

// Upload the file itself
    PFFile *file = [PFFile fileWithName:fileName data:fileData];
    [file saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
        if (error) {
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"An error occured!" message:@"Please try sending your message again.!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alertView show];
        } else {
            // Upload message details
            PFObject *message = [PFObject objectWithClassName:@"Messages"];
            [message setObject:file forKey:@"file"];
            [message setObject:fileType forKey:@"fileType"];
            [message setObject:self.recipients forKey:@"recipientsIds"];
            [message setObject:self.recipientUsernames forKey:@"recipientUsernames"]; //Keeps Breaking here now when user clicks send button in running app. <Exception Breakpoint points me in this line when the app crashes>
            [message setObject:[[PFUser currentUser] objectId] forKey:@"senderId"];
            [message setObject:[[PFUser currentUser] username] forKey:@"senderName"];
            [message saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
                if (error) {
                    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"An error occured!" message:@"Please try sending your message again.!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                    [alertView show];
                } else {
                    // Everything was successful!
                    [self reset];

                }
            }];
        }
    }];

}

// ...

</p>

Anyone have any idea what's going on now?? : /

what does it say when it crashes? can you post

so you have 2 different arrays self.recipients addObject:user.objectId]; [self.recipientUsernames addObject:user.username]

how do you know the fields will match up correctly since they are 2 different lists in 2 different places? i would recommend you to drop the username array and use a pointer to the user using the userIds... in that way you can retrieve the recipients info with your first query.

Stone Preston
Stone Preston
42,016 Points

he isnt going to query on this. As far as I can tell he just wants to be able to see the usernames of the recipients in the data browser on parse in addition to the ids. Yes it would be better to save the user object, but then he wouldnt be able to see all the usernames at once, he would have to click each user object in the data browser.

both arrays are being set with the same data at the same time in didSelectRowAtIndexPath so they should match up

Stone, Ok. Thanks.

Jonathan Fernandez
Jonathan Fernandez
8,325 Points

Yes the goal is simply to see just the recipients' usernames on Parse Dashboard. I've been looking at the code and it really feels like this should make total sense. Shown below is a screenshot of the error I'm getting. I'm still not very good at debugging and sometimes feel really clueless at the interface. If anyone has any suggestions on test or NSLog checks I should be running to help find out what's going wrong I would really appreciate it.

Screenshot Bug

Jonathan Fernandez
Jonathan Fernandez
8,325 Points

Sorry the screenshot took a while to add this image.. I didn't realize you had to upload images to the internet and can't grab them locally.

robert cioffi
robert cioffi
3,466 Points

I have this same problem and haven't been able to get past it, something is wrong with how the recipients are added to Parse. I'm stuck and can't get any further on this app, if I comment out that line you highlighted above my image uploads to Parse.com without recipients....please help anyone