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

thelontx
PLUS
thelontx
Courses Plus Student 2,054 Points

My recipientIds Array is null when passed to Parse. Other fields are okay. Due to Asynch call?

The successful path of my "send" method is set up as in the video:

    else {
        //image or video exists; proceed with send
        [self uploadMessage];
        [self reset];
        [self.tabBarController setSelectedIndex:0];
    }

Following the video, my "reset" helper method clears the image, videoFilePath, and recipients.

- (void)reset {
    self.image=nil;
    self.videoFilePath=nil;
    [self.recipients removeAllObjects];
}

When I run Ribbit like this, all of the data writes to Parse successfully, except for the recipients array. It shows up null. If I comment out the reset method call within the else block above, all of the data writes to Parse.

I can workaround this by approaching the reset in different places. However, I'd like to understand why this is happening for recipients, but does not affect image or videoFilePath. Any ideas? I assume it is related to the asynch call.

Also, I like the "elegance" of simply resetting the values when the upload is successful, instead of having to complicate the code by addressing the reset in other manners.

4 Answers

Sahil Gupta
Sahil Gupta
9,039 Points

Reset the state of your controller in the else block of [message saveInBackgroundWithBlock] method.

Yep. Looks like the reset method is getting called before your 'uploadMessage' method finishes. Maybe you could add a completion block to the 'uploadMessage' call and place the reset method there.

thelontx
thelontx
Courses Plus Student 2,054 Points

Thanks for the confirmation.

Any idea on why this is an issue for the recipients array, but the image and videoFilePath that are handled in the same reset method?

João Maia
João Maia
3,416 Points

I have the same issue and I can't find what am I doing wrong... My code is exactly like in the video and my array of recepientIds is empty all the time.

Stepan Ulyanin
Stepan Ulyanin
11,318 Points

I found a bug in my code as I was still following the instructor, the bug was in this part:

if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {

        //add the objectId of the user object to the recipients list
        [self.recipients addObject:user.objectId];
        cell.accessoryType = UITableViewCellAccessoryNone;
} else {

        //remove the objectId if the user object if deselected
        [self.recipients removeObject:user.objectId];
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
}

As far as I understand it is a logical mistake and you can fix it by adding this after the previous conditional statement:

if ([self.recipients containsObject:user.objectId]) {
        [self.recipients removeObject:user.objectId];
} else {
        [self.recipients addObject:user.objectId];
}

For anyone in the future, or for those currently working on this problem I have a very simple solution. Yes, the answer is that the [self reset]; method is getting called before the block can finish. And while, we don't know how long it takes for a block to finish, we do know where in our code is does finish. First, remove the [self reset]; method from your Send button IBAction. It will be added to your Upload message method instead. like so...

-(void)uploadMessage {
    //check if image or video
    //if image, shrink it
    //upload the file
    //upload the message details
    NSData *fileData;
    NSString *fileName;
    NSString *fileType;
    if (self.image != nil) {
        UIImage *newImage = [self resizeImage:self.image toWidth:320.0f andHeight:480.0f];
        fileData = UIImagePNGRepresentation(newImage);
        fileName = @"image.png";
        fileType = @"image";
    } else {
        fileData = [NSData dataWithContentsOfFile:self.videoFilePath];
        fileName = @"video.mov";
        fileType = @"video";
    }

    PFFile *file = [PFFile fileWithName:fileName data:fileData];
    [file saveInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
        if ( error ) {
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"An error occurred" message:@"Please try sending your message again." delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles:nil, nil];
            [alertView show];
        } else {
            PFObject *message = [PFObject objectWithClassName:@"Messages"];
            [message setObject:file forKey:@"file"];
            [message setObject:fileType forKey:@"fileType"];
            [message setObject:self.recipients forKey:@"recipientIds"];
            [message setObject:[[PFUser currentUser] objectId] forKey:@"senderId"];
            [message setObject:[[PFUser currentUser] username] forKey:@"senderName"];
            [message saveInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {

                if (error) {
                    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"An error occurred" message:@"Please try sending your message again." delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles:nil, nil];
                    [alertView show];
                } else {
                    //do nothing.. send buttons takes user back to the inbox from this point on
                    [self reset];
                }
            }];
        }
    }];
}

As you can see.. I call the reset method when the block is actually finished. So while I don't know how long it will take for the block to finish, i'm basically saying call this reset method whenever you are done. So instead of doing nothing, call your reset method. My parse server now shows the recipients.