1

我必须比现在更难……或者实施我在网上看到的解决方案不正确。

我有一个 URL 数组,我想循环并按顺序将结果推送到字典或数组。如何让它在运行下一个请求之前等待字典更新?基本上我想在后台线程中同步进行调用。

这是我称之为下载的地方:

for (NSString *path in paths) {

    NSURLSession *session = [NSURLSession sessionWithConfiguration [NSURLSessionConfiguration defaultSessionConfiguration]];

    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:path]
                                              cachePolicy:NSURLRequestUseProtocolCachePolicy
                                          timeoutInterval:10];

    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error)
                                                {

                                                }
                                                else
                                                {
                                                    NSError *parsingError = nil;
                                                    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data
                                                                                                         options:NSJSONReadingAllowFragments
                                                                                                           error:&error];
                                                    if (parsingError)
                                                    {

                                                    }
                                                    else
                                                    {
                                                        [myDictionary addObject:dict];
                                                    }
                                                }
                                            }];
    [task resume];
}
4

1 回答 1

2

除非一个请求在发出之前确实需要前一个请求的结果(这里不是这种情况),否则您不应该顺序运行它们。顺序发出可能感觉更合乎逻辑,但这样做会付出巨大的性能损失。同时发布它们,将结果保存在一些无序结构(如字典)中,然后在所有完成后,构建您的有序结构。

NSMutableDictionary *results = [NSMutableDictionary dictionaryWithCapacity:[paths count]];

// don't create new session for each request ... initialize this outside of the loop

NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; // or since you're not doing anything special here, use `sharedSession`

// since we're going to block a thread in the process of controlling the degree of 
// concurrency, let's do this on a background queue; we're still blocking
// a GCD worker thread as these run (which isn't ideal), but we're only using
// one worker thread.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // only do for requests at a time, so create queue a semaphore with set count

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(4); // only do four requests at a time

    // let's keep track of when they're all done

    dispatch_group_t group = dispatch_group_create();

    // now let's loop through issuing the requests

    for (NSString *path in paths) {
        dispatch_group_enter(group);                               // tell the group that we're starting another request

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // wait for one of the four slots to open up

        NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:path]
                                                      cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                  timeoutInterval:10];

        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            if (error) {
                // ...
            } else {
                NSError *parsingError = nil;
                NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
                if (parsingError) {

                } else {
                    // synchronize updating of dictionary

                    dispatch_async(dispatch_get_main_queue(), ^{
                        results[path] = dict;
                    });
                }
            }

            dispatch_semaphore_signal(semaphore);                  // when done, flag task as complete so one of the waiting ones can start
            dispatch_group_leave(group);                           // tell the group that we're done
        }];
        [task resume];
    }

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // trigger whatever you want when they're all done

        // and if you want them in order, iterate through the paths and pull out the appropriate result in order
        for (NSString *path in paths) {
            // do something with `results[path]`
        }
    });
});

我试图在这里减少额外依赖的数量,所以我使用了调度组和信号量。在上面,我使用信号量来约束并发程度,并使用调度组来确定何时完成。

就个人而言,我不会使用信号量和组,而是将这些请求包装在异步NSOperation子类中,但我试图限制我对您的代码所做的更改。但是这个NSOperation想法在逻辑上和上面是一样的:并发运行,但是限制并发的程度,这样你就不会超时了,只有当所有的结果都被检索到时才触发结果的检索。

于 2016-06-28T22:27:23.313 回答