Search code examples
iosobjective-ciphoneipadsdwebimage

dispatch_async(dispatch_get_main_queue() is not working on iPad, but working on iPhone


I am using SDWebImage library and its working on iPhone. But I don't know why this is not called in iPad. I tried to put break points, but it doesn't hit the break point either. I put this method in cellForItemAtIndexPath.

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
     static NSString* cellIdentifier = @"CustomCollectionViewCell";
     CustomCollectionViewCell* cell = (CustomCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
     [cell.downloadButton setTag:indexPath.row];
     [cell.downloadButton addTarget:self action:@selector(deleteButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
     catalogModel = [catalogArray objectAtIndex:indexPath.item];
     cell.cellDescription.text = catalogModel.catalogName;
     SDWebImageManager *manager = [SDWebImageManager sharedManager];
     NSString *urlStr = catalogModel.imageNameThumbnail;
     NSURL *url = [NSURL URLWithString:urlStr];
     dispatch_async(dispatch_get_main_queue(), ^{
             if ([self.catalogCollectionView.indexPathsForVisibleItems containsObject:indexPath])
             {
                  catalogModel = [catalogArray objectAtIndex:indexPath.item];
                  [manager downloadImageWithURL:[NSURL URLWithString:catalogModel.imageNameThumbnail] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {}completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL)
                  {
                       cell.cellImageView.image = image;
                       NSLog(@"%@",catalogModel.catalogName);
                  }];
             };

        });
     return cell;
}

Solution

  • There is a problem in concurrent image loading implementation. When -collectionView: cellForItemAtIndexPath: is calling, the device executes code on the main queue. Assuming that -downloadImageWithURL:options:progress:completed: method performs image loading on the background thread and returns instantly we can call it without dispatch_async(dispatch_get_main_queue()... wrapping. Otherwise we cannot guarantee that the completion handler is executing on the main thread, so the code should look like this

    -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
         static NSString* cellIdentifier = @"CustomCollectionViewCell";
    
         CustomCollectionViewCell* cell = (CustomCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
    
         ...
    
         SDWebImageManager *manager = [SDWebImageManager sharedManager];
    
         // methods with completion block usually return instantly
         [manager downloadImageWithURL:aURL options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize){} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
             // ensure ui is updating on main thread and for visible cell
             dispatch_async(dispatch_get_main_queue(), ^{
                 if ([collectionView.indexPathsForVisibleItems containsObject:indexPath]) {
                     cell.cellImageView.image = image;
                 }
             });
         }];
    
         return cell;
    }
    

    And the different results on iPhone and iPad can be explained by the architectural differences in technical specifications of testing devices.