Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
495 views
in Technique[技术] by (71.8m points)

objective c - Wait for completion block of writeImageToSavedPhotosAlbum by semaphore

In my app I open the camera by a picker and after the photo has been taken I'd like to safe it by the following method the assets library. The method freezes after the call of the writeImageToSavedPhotosAlbum.

Without the semaphores the methods work perfectly. But than I miss to receive the assetURL.

+ (NSURL*)safeImageToAssetsLibrary:(UIImage *)image metadata:(NSDictionary *)metadata
{
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    __block NSURL *retAssestURL = nil;

    dispatch_semaphore_t semaWaitingForSafeImage = dispatch_semaphore_create(0);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // safe the image to the assests library
    NSLog(@"Safe image to asssets library...");

    dispatch_async(queue, ^{
        [library writeImageToSavedPhotosAlbum:image.CGImage metadata:metadata completionBlock:^(NSURL *assetURL, NSError *error) {

            if (error) {
                NSLog(@"Image could not be safed to the assets library: %@", error);
                retAssestURL = nil;
            }
            else {
                NSLog( @"Image safed successfully to assetURL: %@", assetURL);
                retAssestURL = assetURL;
            }

            dispatch_semaphore_signal(semaWaitingForSafeImage);
        }];
    });

    dispatch_semaphore_wait(semaWaitingForSafeImage, DISPATCH_TIME_FOREVER);

    return retAssestURL;
}

And this is method where I call the safeImageToAssetsLibrary method:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    [picker dismissViewControllerAnimated:YES completion:NULL];

    // get chosen image and add thumbnail to collection view
    NSURL *imageUrl        = info[UIImagePickerControllerReferenceURL];
    UIImage *chosenImage   = info[UIImagePickerControllerOriginalImage];

    // safe image to photo library if the camera has been used
    if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
        imageUrl = [BaseImageHandler safeImageToAssetsLibrary:chosenImage metadata:info[UIImagePickerControllerMediaMetadata]];
    }

    // UPDATE View and Core Data here...

}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Do not wait. Never, never do what you are doing. You are failing to understand what "asynchronous" is about. It means that you are called back when it's all over in the completion block. So that is where you perform the next step.

Do NOT try to return a value from a method that obtains that value in an asynchronous completion block.

So, here, in writeImageToSavedPhotosAlbum:'s completion block, that is where you receive retAssestURL. So if there is a further step, now do it, there, in the completion block. This could involve calling another method or whatever you like, but the point is, things will now happen in the correct order.

And above all, Do NOT use semaphores (or other trickery) to try to turn asynchronous into synchronous. Asynchronous things are asynchronous for a reason. Use the framework, don't fight it. (Actually, what you are doing with semaphores here is not just fighting the framework but spitting in its eye.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...