0

I'm using JSQMessage and am having a little difficulty with showing the placeholder for media until I have it correctly downloading, and then replacing with the media. I have everything working correctly as far as adding the messages and media to server, I just can't get it to replace the placeholders.

Currently, I have a function that queries my database and pulls an array of objects for messages and then loops through and calls this function for each object to output and add it to my message thread. I'm struggling to figure out why the section with "messageToAdd.isMediaMessage" is not replacing the placeholders with the actual media following it's download from the server. Does anyone know how I should be handling this to make sure it adds the message with a placeholder, and then replaces once the media is downloaded correctly?

- (void)addMessage:(PFObject *)object
{
    id<JSQMessageMediaData> messageMedia = nil;
    PFObject *user = object[@"messageSender"];
    [users addObject:user];
    NSString *name = @"";
    if(user[@"profileFName"] && user[@"profileLName"])
        name= [NSString stringWithFormat:@"%@ %@",user[@"profileFName"],user[@"profileLName"]];
    else
        name= [NSString stringWithFormat:@"%@ %@",user[@"consultantFName"],user[@"consultantLName"]];

    if([object[@"messageFileType"] isEqual: @"video"]){
        JSQVideoMediaItem *messageMedia = [[JSQVideoMediaItem alloc] init];
        messageMedia.fileURL = nil;
        messageMedia.isReadyToPlay = NO;
        messageToAdd = [JSQMessage messageWithSenderId:user.objectId displayName:name media:messageMedia];

    } else if ([object[@"messageFileType"] isEqual: @"image"]){
        JSQPhotoMediaItem *messageMedia = [[JSQPhotoMediaItem alloc] init];
        messageMedia.image = nil;
        messageToAdd = [JSQMessage messageWithSenderId:user.objectId displayName:name media:messageMedia];

    } else{
        messageToAdd= [[JSQMessage alloc] initWithSenderId:user.objectId senderDisplayName:name date:object[@"sendDate"] text:object[@"messageContent"]];
    }
    if(isLoadMore)
        [messages insertObject:messageToAdd atIndex:0];
    else
        [messages addObject:messageToAdd];

   // NOT TRIGGERING THESE AFTER MEDIA DOWNLOADED
    if (messageToAdd.isMediaMessage) {
        dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
            if ([object[@"messageFileType"] isEqual: @"image"]){
                [object[@"messageMedia"] getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
                    if (!error) {
                        JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] initWithImage:[UIImage imageWithData:imageData]];
                        ((JSQPhotoMediaItem *)messageMedia).image = [UIImage imageWithCGImage:photoItem.image.CGImage];
                        [self.collectionView reloadData];
                    }
                }];
            }
            else if([object[@"messageFileType"] isEqual: @"video"]){
                PFFile *videoFile = object[@"messageMedia"];
                NSURL *videoURL = [NSURL URLWithString:videoFile.url];
                ((JSQVideoMediaItem *)messageMedia).fileURL = videoURL;
                ((JSQVideoMediaItem *)messageMedia).isReadyToPlay = YES;
                [self.collectionView reloadData];
            }
            else {
                NSLog(@"%s error: unrecognized media item", __PRETTY_FUNCTION__);
            }
        });
    }
}
Jake Lisby
  • 494
  • 5
  • 21

2 Answers2

1

For others who come along with the same issue/question, I resolved how it was working by looking at the project NotificationChat here:https://github.com/relatedcode/NotificationChat/blob/master/NotificationChat/Classes/Chat/ChatView.m. It gives a really good overview of using the JSQMessage platform.

Here's my modified function so you can see the finished product.

- (void)addMessage:(PFObject *)object
{
    PFObject *user = object[@"messageSender"];
    [users addObject:user];

    PFFile *mediaMessage = object[@"messageMedia"];

    NSString *name = @"";
    if(user[@"profileFName"] && user[@"profileLName"])
        name= [NSString stringWithFormat:@"%@ %@",user[@"profileFName"],user[@"profileLName"]];
    else
        name= [NSString stringWithFormat:@"%@ %@",user[@"consultantFName"],user[@"consultantLName"]];

    if([object[@"messageFileType"] isEqual: @"video"]){
        JSQVideoMediaItem *mediaItem = [[JSQVideoMediaItem alloc] initWithFileURL:[NSURL URLWithString:mediaMessage.url] isReadyToPlay:YES];
        mediaItem.appliesMediaViewMaskAsOutgoing = [user.objectId isEqualToString:self.senderId];
        messageToAdd = [[JSQMessage alloc] initWithSenderId:user.objectId senderDisplayName:name date:object.createdAt media:mediaItem];

    } else if ([object[@"messageFileType"] isEqual: @"image"]){
        JSQPhotoMediaItem *mediaItem = [[JSQPhotoMediaItem alloc] initWithImage:nil];
        mediaItem.appliesMediaViewMaskAsOutgoing = [user.objectId isEqualToString:self.senderId];
        messageToAdd = [[JSQMessage alloc] initWithSenderId:user.objectId senderDisplayName:name date:object.createdAt media:mediaItem];

        [mediaMessage getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error)
         {
             if (error == nil)
             {
                 mediaItem.image = [UIImage imageWithData:imageData];
                 [self.collectionView reloadData];
             }
         }];


    } else{
        messageToAdd= [[JSQMessage alloc] initWithSenderId:user.objectId senderDisplayName:name date:object[@"sendDate"] text:object[@"messageContent"]];
    }
    if(isLoadMore)
        [messages insertObject:messageToAdd atIndex:0];
    else
        [messages addObject:messageToAdd];

}
Jake Lisby
  • 494
  • 5
  • 21
0

Based on the code I think one possible reason is you need reloadData on main(UI) thread after download data successfully and asynchronously on background thread

dopcn
  • 4,218
  • 3
  • 23
  • 32
  • Hmm, I tried updating to the following, but to no avail. Is there something I need to do with reloadData? Here's what I added: `dispatch_async(dispatch_get_main_queue(), ^(void){ //Run UI Updates [self.collectionView reloadData]; });` – Jake Lisby Mar 27 '15 at 13:26
  • To clarify, I used the structure here http://stackoverflow.com/questions/16283652/understanding-dispatch-async – Jake Lisby Mar 27 '15 at 13:27