Ios 使用grand central dispatch下载UIImage

Ios 使用grand central dispatch下载UIImage,ios,objective-c,asynchronous,uiimage,grand-central-dispatch,Ios,Objective C,Asynchronous,Uiimage,Grand Central Dispatch,我有一个URL,当复制到浏览器中时,它会显示一个图像。我的函数应该异步下载映像 - (UIImage *)downloadImage:(NSString *)imageURL { NSError *error = nil; NSURL *urlString = [NSURL URLWithString:imageURL]; NSData *data = [NSData dataWithContentsOfURL:urlString options:NSDataReadin

我有一个URL,当复制到浏览器中时,它会显示一个图像。我的函数应该异步下载映像

- (UIImage *)downloadImage:(NSString *)imageURL
{
    NSError *error = nil;
    NSURL *urlString = [NSURL URLWithString:imageURL];
    NSData *data = [NSData dataWithContentsOfURL:urlString options:NSDataReadingUncached error:&error];
    __block UIImage *image;

    if (!error) {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(queue, ^{
            image = [UIImage imageWithData:data];
        });
        return image;
    } else {
        NSLog(@"%@", [error localizedDescription]);
    }
    return nil;
}
当我尝试在
UIImageView
中显示图像时,没有任何错误,也没有任何结果。我已经注销了
数据
和传入的
imageURL
,并且没有一个是空的


有什么建议吗?

通过调用
dispatch\u async
,您可以将工作安排在以后进行。在该工作完成之前,函数将以nil退出。在接收并处理图像数据之前,您需要向函数中添加回调块或使其成为块

下面是一个带有块回调的函数示例,以及如何使用它

- (void)downloadImageAtURL:(NSString *)imageURL withHandler:(void(^)(UIImage *image))handler
{
    NSURL *urlString = [NSURL URLWithString:imageURL];

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSError *error = nil;
        NSData *data = [NSData dataWithContentsOfURL:urlString options:NSDataReadingUncached error:&error];
        if (!error) {
            UIImage *downloadedImage = [UIImage imageWithData:data];
            handler(downloadedImage); // pass back the image in a block
        } else {
            NSLog(@"%@", [error localizedDescription]);
            handler(nil); // pass back nil in the block
        }
    });
}



- (void)keyboardDidShow:(NSNotification *)aNotification {
    [self downloadImageAtURL:@"" withHandler:^(UIImage *image) {
        if (image) {
            // display
        } else {
            // handle probelm
        }
    }];
}

通过调用
dispatch\u async
,您可以将该工作安排在以后进行。在该工作完成之前,函数将以nil退出。在接收并处理图像数据之前,您需要向函数中添加回调块或使其成为块

下面是一个带有块回调的函数示例,以及如何使用它

- (void)downloadImageAtURL:(NSString *)imageURL withHandler:(void(^)(UIImage *image))handler
{
    NSURL *urlString = [NSURL URLWithString:imageURL];

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSError *error = nil;
        NSData *data = [NSData dataWithContentsOfURL:urlString options:NSDataReadingUncached error:&error];
        if (!error) {
            UIImage *downloadedImage = [UIImage imageWithData:data];
            handler(downloadedImage); // pass back the image in a block
        } else {
            NSLog(@"%@", [error localizedDescription]);
            handler(nil); // pass back nil in the block
        }
    });
}



- (void)keyboardDidShow:(NSNotification *)aNotification {
    [self downloadImageAtURL:@"" withHandler:^(UIImage *image) {
        if (image) {
            // display
        } else {
            // handle probelm
        }
    }];
}

对dataWithContentsOfURL:options:error:的调用需要在dispatch_队列块内,才能使其异步。对UI的任何更改都需要在主线程中进行。它应该是这样的:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^(void) {

        NSData *imageData = [NSData dataWithContentsOfURL:imageURL];

        UIImage* image = [[UIImage alloc] initWithData:imageData];
        if (image) {
             dispatch_async(dispatch_get_main_queue(), ^{
                    //load image into UIImageView
                 }
             });
         }
    });
- (void)downloadImage:(NSString *)imageURL onComplete:(void (^)(UIImage *, NSError * error))onComplete
{
    NSURL *urlString = [NSURL URLWithString:imageURL];

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSError *error = nil;
        NSData *data = [NSData dataWithContentsOfURL:urlString options:NSDataReadingUncached error:&error];
        image = [UIImage imageWithData:data];
        if (onComplete) {
          // Keep in mind that onComplete block will be called on a background thread.
          // If you need to use it on UIImageView, you must set it on main thread.
          onComplete(image, error); 
        }            
    });
}

对dataWithContentsOfURL:options:error:的调用需要在dispatch_队列块内,才能使其异步。对UI的任何更改都需要在主线程中进行。它应该是这样的:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^(void) {

        NSData *imageData = [NSData dataWithContentsOfURL:imageURL];

        UIImage* image = [[UIImage alloc] initWithData:imageData];
        if (image) {
             dispatch_async(dispatch_get_main_queue(), ^{
                    //load image into UIImageView
                 }
             });
         }
    });
- (void)downloadImage:(NSString *)imageURL onComplete:(void (^)(UIImage *, NSError * error))onComplete
{
    NSURL *urlString = [NSURL URLWithString:imageURL];

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSError *error = nil;
        NSData *data = [NSData dataWithContentsOfURL:urlString options:NSDataReadingUncached error:&error];
        image = [UIImage imageWithData:data];
        if (onComplete) {
          // Keep in mind that onComplete block will be called on a background thread.
          // If you need to use it on UIImageView, you must set it on main thread.
          onComplete(image, error); 
        }            
    });
}

您没有异步下载映像。此外,假定以异步方式返回值的方法不能通过返回值的方法返回该值,但应该使用块返回该值

您可以尝试这样做:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^(void) {

        NSData *imageData = [NSData dataWithContentsOfURL:imageURL];

        UIImage* image = [[UIImage alloc] initWithData:imageData];
        if (image) {
             dispatch_async(dispatch_get_main_queue(), ^{
                    //load image into UIImageView
                 }
             });
         }
    });
- (void)downloadImage:(NSString *)imageURL onComplete:(void (^)(UIImage *, NSError * error))onComplete
{
    NSURL *urlString = [NSURL URLWithString:imageURL];

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSError *error = nil;
        NSData *data = [NSData dataWithContentsOfURL:urlString options:NSDataReadingUncached error:&error];
        image = [UIImage imageWithData:data];
        if (onComplete) {
          // Keep in mind that onComplete block will be called on a background thread.
          // If you need to use it on UIImageView, you must set it on main thread.
          onComplete(image, error); 
        }            
    });
}
然后,当需要设置UIImageView图像时:

__weak typeof(self)selfB = self; // Better to use a weak reference inside blocks to avoid retain cycles
[self downloadImage:myURLString onComplete:^(UIImage * image, NSError * error) {
    dispatch_async(dispatch_get_main_queue(), ^{ // As you can see, we use main thread for UI updates
        selfB.imageView.image = image;
    });
}];

您没有异步下载映像。此外,假定以异步方式返回值的方法不能通过返回值的方法返回该值,但应该使用块返回该值

您可以尝试这样做:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^(void) {

        NSData *imageData = [NSData dataWithContentsOfURL:imageURL];

        UIImage* image = [[UIImage alloc] initWithData:imageData];
        if (image) {
             dispatch_async(dispatch_get_main_queue(), ^{
                    //load image into UIImageView
                 }
             });
         }
    });
- (void)downloadImage:(NSString *)imageURL onComplete:(void (^)(UIImage *, NSError * error))onComplete
{
    NSURL *urlString = [NSURL URLWithString:imageURL];

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSError *error = nil;
        NSData *data = [NSData dataWithContentsOfURL:urlString options:NSDataReadingUncached error:&error];
        image = [UIImage imageWithData:data];
        if (onComplete) {
          // Keep in mind that onComplete block will be called on a background thread.
          // If you need to use it on UIImageView, you must set it on main thread.
          onComplete(image, error); 
        }            
    });
}
然后,当需要设置UIImageView图像时:

__weak typeof(self)selfB = self; // Better to use a weak reference inside blocks to avoid retain cycles
[self downloadImage:myURLString onComplete:^(UIImage * image, NSError * error) {
    dispatch_async(dispatch_get_main_queue(), ^{ // As you can see, we use main thread for UI updates
        selfB.imageView.image = image;
    });
}];

如其他人的回答所示,您可能希望返回块中的错误(如果有)。此外,您应该签出NSURLSession并下载任务。使用
dataFromURL
,您正在将所有图像数据加载到内存中,这可能会导致问题(图像太大)。您可能希望返回块中的任何错误,如其他人的回答所示。此外,您应该签出NSURLSession并下载任务。使用
dataFromURL
,您正在将所有图像数据加载到内存中,这可能会导致问题(图像很大)。