6

I am trying to implement asynchronous url requests in a particular function, I want all these requests to complete and then do a particular action but the action precedes the requests i.e, it is getting called before the requests complete.

dispatch_queue_t fetchQ = dispatch_queue_create("Featured Doc Downloader", NULL);
        dispatch_async(fetchQ, ^{
            [self myAsyncMultipleURLRequestFunction];
            dispatch_sync(dispatch_get_main_queue(), ^{
                [self updateUIFunction];
            });
        });

-(void)myAsyncMultipleURLRequestFunction
   {
    for (int i=0; i<count; i++) 
     {
     NSURLConnection *loginConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];          
     }
   }

now updateUIFunction gets called before myAsyncMultipleURLRequestFunction completes all requests. Also tried this with NSOperaitonQueue but could not do what I really want.

[_operationQ addOperationWithBlock: ^ {
     for (int i=0; i<count; i++)
      {
     NSURLConnection *loginConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];          
      }
    }

[[NSOperationQueue mainQueue] addOperationWithBlock: ^ {
         // updating UI
         [self updateUIFunction];
    }];
}];

I know this is simple but I am running outta time, any help is appreciated.

Satheesh
  • 10,998
  • 6
  • 50
  • 93

3 Answers3

10

@tkanzakic is on the right path. The correct construct to use is the dispatch_group_t. But the implementation could be improved. By using a semaphore you can launch all your downloads asynchronously and still make sure that you don't have too many running concurrently. Here is a code sample that illustrates how you should use dispatch_group_t as well as make all your downloads parallel:

dispatch_queue_t fetchQ = dispatch_queue_create("Featured Doc Downloader", NULL);
dispatch_group_t fetchGroup = dispatch_group_create();

// This will allow up to 8 parallel downloads.
dispatch_semaphore_t downloadSema = dispatch_semaphore_create(8);

// We start ALL our downloads in parallel throttled by the above semaphore.
for (int i=0; i<count; i++) {
    dispatch_group_async(fetchGroup, fetchQ, ^(void) {
        dispatch_semaphore_wait(downloadSema, DISPATCH_TIME_FOREVER);
        NSURLConnection *loginConnection = [[NSURLConnection alloc] initWithRequest:requestArray[i] delegate:self];
        dispatch_semaphore_signal(downloadSema);
    });
}

// Now we wait until ALL our dispatch_group_async are finished.
dispatch_group_wait(fetchGroup, DISPATCH_TIME_FOREVER);

// Update your UI
dispatch_sync(dispatch_get_main_queue(), ^{
    [self updateUIFunction];
});

// Release resources
dispatch_release(fetchGroup);
dispatch_release(downloadSema);
dispatch_release(fetchQ);
aLevelOfIndirection
  • 3,522
  • 14
  • 18
3

You can create a dispatch_group_t and then use dispatch_group_notify to execute the updateUIFunction when the previous block of the group finish running, for example:

dispatch_queue_t fetchQ = dispatch_queue_create("Featured Doc Downloader", NULL);
dispatch_async(fetchQ, ^{
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        [self myAsyncMultipleURLRequestFunction];
    });
    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateUIFunction];
        });
    });
});
tkanzakic
  • 5,499
  • 16
  • 34
  • 41
  • Thanks will try this and let you know! – Satheesh Apr 17 '13 at 07:52
  • Hey @tkanzakic it is not working, same as before. updateUIFUnction gets called before myAsyncMultipleURLRequestFunction gets completed. – Satheesh Apr 17 '13 at 08:54
  • I have made a small modification of the `dispatch_group_notify` block, I remember that I need to implement it this way is some project, give it a try – tkanzakic Apr 17 '13 at 09:06
  • by the way, are your connections running asynchronously? – tkanzakic Apr 17 '13 at 09:07
  • Yes all connections are asynchronous. – Satheesh Apr 17 '13 at 09:11
  • That's the reason why this is not working (and this way will be not possible to accomplish this), the `dispatch_group_notify` wait for the end of the method `myAsyncMultipleURLRequestFunction` but not for the downloads. To solve this you can try to create a callback in your connections delegate – tkanzakic Apr 17 '13 at 09:26
  • I guess now you have got the context, I have a list of connections and I dont think creating callbacks for every single connection is a viable approach. Is there any other way to do it? – Satheesh Apr 17 '13 at 09:33
  • all your connection share the delegate?, you can check when all of them are finished and then call your callback function (delegate) function – tkanzakic Apr 17 '13 at 09:49
  • How to check whether all o'em got completed??. – Satheesh Apr 17 '13 at 10:07
  • you know the number of `NSURLConnection` you are running, create a local property numberOfConnectionFinished and in the method `connectionDidFinishLoading:` increase its value, you will have to did it in the `connection:didFailWithError:` for the case some of your connection fail – tkanzakic Apr 17 '13 at 10:13
1

First Configure run loop.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
    [NSURLConnection connectionWithRequest:request delegate:self];
    while(!self.finished) {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
});

Try this

Satheesh
  • 10,998
  • 6
  • 50
  • 93
user2243325
  • 41
  • 1
  • 6