Get image data for pins on a MapView without blocking main thread problem

Discussion in 'iOS Programming' started by pan17, Jul 25, 2012.

  1. pan17 macrumors newbie

    Joined:
    Jul 9, 2012
    #1
    I implement a UIViewController which shows the MapView delegate method in another UIViewController, I'm trying to get the image from Internet when a pin is clicked by user in that MapView by returning the image for that method, but it blocked the main thread so that the whole MapView is blocked by that method. I'm just wondering if there is a way to solve this problem. The following is my method:

    Code:
    // PhotoMapViewControllerDelegate method to get the clicked thumbnail image
    - (UIImage *)photoMapViewController:(PhotoMapViewController *)sender imageForAnnotation:(id<MKAnnotation>)annotation
    {   
        SinglePlacePhotosAnnotations *sppa = (SinglePlacePhotosAnnotations *)annotation;
        // check out the folder if the photo already exists
        NSFileManager *filemanager = [NSFileManager defaultManager];
        NSURL *libraryURL = [[filemanager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];
        NSURL *photosURL = [libraryURL URLByAppendingPathComponent:@"Viewd Photos"];
        NSString *photoID = [sppa.photo objectForKey:FLICKR_PHOTO_ID];
        NSURL *singlePhotoURL = [photosURL URLByAppendingPathComponent:photoID];
        dispatch_queue_t getImage = dispatch_queue_create("getImage", NULL);
        // local variables in a block is read-only!!!!!!!!!!!
        __block UIImage *image = nil;
        // use a variable to check if the block is done
        __block BOOL blockIsDone = NO;
        dispatch_async(getImage, ^ { 
            if ([filemanager fileExistsAtPath:singlePhotoURL.path]) { 
                image = [UIImage imageWithContentsOfFile:singlePhotoURL.path];
                blockIsDone = YES;
            }
            else {
                NSURL *url = [FlickrFetcher urlForPhoto:sppa.photo format:FlickrPhotoFormatSquare];
                NSData *data = [NSData dataWithContentsOfURL:url];
                image = [UIImage imageWithData:data]; 
                blockIsDone = YES;
            }
        });
        // block makes it asynchronous like the completion handler, this function returns image before the block
        // is done, so have to wait until the block got executed!
        while (!blockIsDone) {
            usleep(USEC_PER_SEC/10);
        }
        return image;
    }
    Thanks in advance.
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    Your dispatch async is essentially useless as you then implement your own blocking until it is complete. You need to use a callback or similar once the data is complete to display it.
     
  3. pan17 thread starter macrumors newbie

    Joined:
    Jul 9, 2012
    #3
    When i scroll down, some new cells still showed the previous cells' corresponding image, then later it will change into the new images. I think this is because when i scroll down showing new table cells, the previous get image data lines which are called in the dispatch block just got the data when i didn't scroll down and set the image.
    I'm looking for some methods which could let me scroll down and when the previous image data returned, set the image to the specific old one.
    So, as you said, i need a callback function to get the old image data for the previous table cells it showed,right?
    Thank you for your time.
     
  4. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    I am struggling to understand what you mean. You probably need to break this down:

    1) Get the view working correctly so no cell ever shows the incorrect data. When you are asked to provide a cell for a table row then it's up to you to reset the image etc. Cells get re-used so if you set the image to X and don't ever unset it then it will still display this when that's not correct

    2) Have some sort of model class that does the loading of images and sends notifications to the delegate/caller class when images that were not immediately available get downloaded

    3) Have the table view controller use 2) and update/refresh the cells when images become available

    There are no pre-built methods: you do this yourself.
     
  5. pan17 thread starter macrumors newbie

    Joined:
    Jul 9, 2012
    #5
    Sorry about that. This is clear and helpful.
    Thank you
     

Share This Page