Search code examples
iosuiimagejsqmessagesviewcontroller

Loading a remote image is breaking JSQMessagesAvatarImageFactory


When I attempt to load a remote image for an avatar the app is crashing with an error saying my image cannot be nil. I am simply adding the avatar creation in my ViewDidLoad method for the time being

- (void)viewDidLoad {
    [super viewDidLoad];

    self.inputToolbar.contentView.textView.pasteDelegate = self;
    self.userAvatarDictionary = [[NSMutableDictionary alloc] init];
    self.latestGuid = @"";

    /**
     *  Load up our fake data for the demo
     */
    self.demoData = [[DemoModelData alloc] init];

    /**
     *  You can set custom avatar sizes
     */

    self.collectionView.collectionViewLayout.incomingAvatarViewSize = CGSizeMake(30, 30);

    self.collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero;

    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage jsq_defaultTypingIndicatorImage]
                                                                              style:UIBarButtonItemStylePlain
                                                                             target:self
                                                                             action:@selector(receiveMessagePressed:)];


    //Load remote image for Gibson Les Paul Guitar as test
    NSString *imgURLString = @"http://images.gibson.com/Products/Electric-Guitars/Les-Paul/Gibson-USA/Les-Paul-Studio/Splash-02.jpg";

    NSURL *url = [NSURL URLWithString:imgURLString];
    NSLog(@"CREATED USER ID: 13");
    NSLog(@"CREATOR IMAGE URL: %@", imgURLString);
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *dataLoadedImg = [UIImage imageWithData:data];


    JSQMessagesAvatarImage *img = [JSQMessagesAvatarImageFactory avatarImageWithImage:dataLoadedImg diameter:20.0f];

    [self.userAvatarDictionary setObject:img forKey:@"13"];
    NSLog(@"ADDED GIBSON ICON SUCCESSFULLY");
    [self callViewMessagesListWithLatestMessageGuid:self.latestGuid
                                    CompletionBlock:^(NSMutableArray *resultsArray) {
                                        [self reloadData:resultsArray];
                                    }];
    [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:@selector(fifteenSecondsPassed:) userInfo:nil repeats:YES];
}

The app is crashing before getting to the success log, and obviously the message loading web service isn't getting called.

Logging/Error messaging:

CREATED USER ID: 13
CREATOR IMAGE URL: http://images.gibson.com/Products/Electric-Guitars/Les-Paul/Gibson-USA/Les-Paul-Studio/Splash-02.jpg

*** Assertion failure in +[JSQMessagesAvatarImageFactory jsq_circularImage:withDiameter:highlightedColor:], /Users/propstm/Documents/Github/MyProject/Pods/JSQMessagesViewController/JSQMessagesViewController/Factories/JSQMessagesAvatarImageFactory.m:132
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: image != nil'

Solution

  • This is because your image is not loaded at the time the view wants it. This can be solved by using a default image to stand in till you can get your image back. You can create a method for giving you a default blank avatar that you use initially then if your request returns update the avatar for that cell.

    func getBlankAvatar() -> UIImage {
       let blankAvatar =  JSQMessagesAvatarImageFactory.avatarImageWithUserInitials("?", backgroundColor: .gray, textColor: .white, font: UIFont.systemFontOfSize(14), diameter: UInt(kJSQMessagesCollectionViewAvatarSizeDefault))
    

    Also as an optimization if you create a dictionary for users in the conversation and get the remote images for them and save it to this dictionary then you only need to make the request once and can pull from that dictionary for your individual message cells.

    🖖🏽