1

基本上,我有一个 url 数组作为字符串,当我遍历这个数组时,如果元素是图像的 url,我想将该 url 转换为 UIImage 对象并将其添加到另一个数组中。这很慢,因为我必须为每个 URL 请求数据。我已经尝试使用如下所示的 dispatch_async ,但它似乎根本没有任何区别。

关键是当我将这些对象添加到我的另一个数组时,无论它们是图像还是其他东西,它们都必须保持有序。任何人都可以提供任何指导吗?

dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i=0; i<[slides count]; i++){
        __block NSString *mediaURLString = [primaryPhoto objectForKey:@"url"];

        if ([self mediaIsVideo:mediaURLString]){
              ***some code***
        }
        else{ //if media is an image
            dispatch_group_async(group, queue, ^{

                mediaURLString = [mediaURLString stringByAppendingString:@"?w=1285&h=750&q=150"];
                NSURL *url = [NSURL URLWithString:mediaURLString];
                [mutableMedia addObject:url];
                NSURL *url = ((NSURL *)self.mediaItem);
                NSURLRequest *request = [NSURLRequest requestWithURL:url];
                NSURLResponse *response;
                NSError *error;
                NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

                UIImage *image = [[UIImage alloc] initWithData:urlData];
                [mutableMedia replaceObjectAtIndex:i withObject:image];
            });
        }
    }
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
4

3 回答 3

1

尝试这个:

[self performSelectorInBackground:@selector(WebServiceCallMethod) withObject:nil];

并创建一个这样的方法

-(void)WebServiceCallMethod
{
                mediaURLString = [mediaURLString stringByAppendingString:@"?w=1285&h=750&q=150"];
                NSURL *url = [NSURL URLWithString:mediaURLString];
                [mutableMedia addObject:url];
                NSURL *url = ((NSURL *)self.mediaItem);
                NSURLRequest *request = [NSURLRequest requestWithURL:url];
                NSURLResponse *response;
                NSError *error;
                NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

                UIImage *image = [[UIImage alloc] initWithData:urlData];
                [mutableMedia replaceObjectAtIndex:i withObject:image];
}

希望能帮助到你!!

于 2013-07-31T04:42:51.757 回答
1

帮自己一个忙,不要使用+sendSynchronousRequest:... 尝试这样的方法:

dispatch_group_t group = dispatch_group_create();
for (int i=0; i<[slides count]; i++)
{
    __block NSString *mediaURLString = [primaryPhoto objectForKey:@"url"];
    if ([self mediaIsVideo:mediaURLString]){
        ***some code***
    }
    else
    {
        //if media is an image
        mediaURLString = [mediaURLString stringByAppendingString:@"?w=1285&h=750&q=150"];
        NSURL *url = [NSURL URLWithString:mediaURLString];
        [mutableMedia addObject:url];
        NSURL *url = ((NSURL *)self.mediaItem);
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        dispatch_group_enter(group);
        [NSURLConnection sendAsynchronousRequest: request queue: [NSOperationQueue mainQueue] completionHandler:
         ^(NSURLResponse *response, NSData *data, NSError *connectionError)
         {
             if (data.length && nil == connectionError)
             {
                 UIImage *image = [[UIImage alloc] initWithData:data];
                 [mutableMedia replaceObjectAtIndex:i withObject:image];
             }
             dispatch_group_leave(group);
         }];
    }
}

dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // Do stuff here that you want to have happen after all the images are loaded.
});

这将为您的所有 URL 启动异步请求。当每个请求完成时,它将运行其完成处理程序,该处理程序将更新您的数组,并且当所有请求完成时,dispatch_group_notify调用中的块将被执行。

这种方法的优点是您可以从主线程调用它,所有单独的完成块都将在主线程上运行(从而确保mutableMedia数组的线程安全(至少就这段代码而言))和最终完成块也将在主线程上运行,因此您可以执行任何需要直接更新 UI 的操作。

于 2013-07-31T12:40:14.350 回答
0

有一个使用 dispatch lib 的绝妙解决方案。下面的代码应该代表自己。

基本思想是数组包含“输入”对象,每个对象都将通过异步一元任务“转换” - 一个接一个。整个操作的最终结果是转换后的对象数组。

这里的一切都是异步的。每个最终结果都将在完成处理程序中传递,这是一个将结果作为参数传递给调用站点的块:

typedef void (^completion_t)(id result);

异步转换函数是一个块,它将输入作为参数并通过完成处理程序返回一个新对象:

typedef void (^unary_async_t)(id input, completion_t completion);

现在,该函数transformEach将输入值作为NSArray参数inArray,将变换块作为参数transform,将完成处理程序块作为参数completion

static void transformEach(NSArray* inArray, unary_async_t transform, completion_t completion);

实现如下:

static void do_each(NSEnumerator* iter, unary_async_t transform, 
  NSMutableArray* outArray, completion_t completion)
{
    id obj = [iter nextObject];
    if (obj == nil) {
        if (completion)
            completion([outArray copy]);
        return;
    }
    transform(obj, ^(id result){
        [outArray addObject:result];
        do_each(iter, transform, outArray, completion);
    });
}

static void transformEach(NSArray* inArray, unary_async_t transform, 
  completion_t completion) {
    NSMutableArray* outArray = [[NSMutableArray alloc] initWithCapacity:[inArray count]];
    NSEnumerator* iter = [inArray objectEnumerator];
    do_each(iter, transform, outArray, completion);
}

并构建并运行以下示例

int main(int argc, const char * argv[])
{
    @autoreleasepool {

        // Example transform:
        unary_async_t capitalize = ^(id input, completion_t completion) {
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
               sleep(1);
                if ([input respondsToSelector:@selector(capitalizedString)]) {
                    NSLog(@"processing: %@", input);
                    NSString* result = [input capitalizedString];
                    if (completion)
                        completion(result);
                }
            });
        };


        transformEach(@[@"a", @"b", @"c"], capitalize, ^(id result){
            NSLog(@"Result: %@", result);
        });
        sleep(10);        
    }
    return 0;
}

将其打印到控制台:

2013-07-31 15:52:49.786 Sample2[1651:1603] processing: a
2013-07-31 15:52:50.789 Sample2[1651:1603] processing: b
2013-07-31 15:52:51.792 Sample2[1651:1603] processing: c
2013-07-31 15:52:51.793 Sample2[1651:1603] Result: (
    A,
    B,
    C
)

您可以轻松地为它创建一个类别NSArray,例如

-(void) asyncTransformEachWithTransform:(unary_async_t)transform completion:(completion_t)completionHandler;

方法。

玩得开心!;)


编辑:

如果您问这如何适用于您的问题:

URL 数组是输入数组。为了创建转换块,只需将您的异步网络请求包装在异步方法中,例如:

`-(void) fetchImageWithURL:(NSURL*)url completion:(completion_t)completionHandler;`

然后将方法包装fetchImageWithURL:completion:到适当的转换块中:

 unary_async_t fetchImage = ^(id url, completion_t completion) {
    [self fetchImageWithURL:url completion:^(id image){
        if (completion) 
            completion(image);  // return result of fetch request
    }];
};

然后,假设您实现了类别 for NSArray,并且您的 url 数组是 property ,则在您的代码中的某处(可能是视图控制器) urls

// get the images
[self.urls asyncTransformEachWithTransform:fetchImage completion:^(id arrayOfImages) {
     // do something with the array of images
}];
于 2013-07-31T14:27:25.433 回答