Adding a new row in a UITableView - iphone

HI Everyone,
It is my first post here and this is my problem:
I am trying to get some data from a REST API call and show then in a UITableView.
This s what I am doing:
in the viewDidLoad: 1) here I initialize my array of things to show in the Table (that is empty at the beginning) 2) the table is loaded (with 0 rows) and 3) then the HTTP async call is issued.
Done this I do my stuff with the HTTP Response and when ready I call the reloadData on my table. Here the strange happens.
numberOfRowsInSelection returns me the correct number of rows
but
tableView:cellForRowAtIndexPath:indexPath for the indexPath.row always returns me zero!
so no new row is added to the table.
- (void)doJSONRequest{
responseData = [[NSMutableData data] retain];
NSString *addr = [[NSString alloc] initWithFormat:#"http://localhost:8080/blabla/v1/items?count=10"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:addr]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[addr release];
}
- (void)doJSONRequestWithURL:(NSString *)url{
responseData = [[NSMutableData data] retain];
NSString *addr = [[NSString alloc] initWithFormat:url];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:addr]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[addr release];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
//NSLog(#"[%#] connection:didReceiveResponse %#",[self class], response);
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
//NSLog(#"[%#] connection:didReceiveData %#",[self class], data);
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"[%#]",[NSString stringWithFormat:#"Connection failed: %#", [error description]]);
UIAlertView *alert = [[UIAlertView alloc] init];
[alert setTitle:#"NETWORK ERROR!"];
[alert setMessage:#"App will close"];
[alert setDelegate:self];
[alert addButtonWithTitle:#"Close"];
[alert show];
[alert release];
[alert show];
[alert release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//NSLog(#"[%#] connectionDidFinishLoading %#",[self class], connection);
[connection release];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSDictionary *res = [NSDictionary dictionaryWithDictionary:[responseString JSONValue]];
NSDictionary *tmp = [res valueForKey:#"reviews"];
tmp = [tmp valueForKey:#"reviews"];
NSEnumerator *e = [tmp objectEnumerator];
NSDictionary *tmp_review;
int i=0;
while (tmp_review = [e nextObject]) {
//NSLog(#"tmp_review %#", tmp_review);
//NSLog(#"count %d", i++);
MyObject r = [... doing my staff...]
[reviews addObject: r];
[r release];
};
[reviewListTableView reloadData];
[responseString release];
}
- (void)viewDidLoad {
//- (void)initUI {
//review is the array where I put my data
//it is empty at the beginning
reviews = [[NSMutableArray alloc] initWithObjects:nil];
[super viewDidLoad];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [reviews count]
}

Sounds like you may not have properly implemented numberOfSectionsInTableView:. You should log indexPath.section in tableView:cellForRowAtIndexPath:indexPath to see what section value you are passing. You will have multiple indexPath.row values of zero because there is a zero row for each section.

add new object in the array and [mytableview reloadData];

Implement following data source return number of section to be present in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
In tableView:cellForRowAtIndexPath:indexPath check section number and do your operation.
Note: If you don't need sections you can remove it.

Related

How to fetch the data from Google news by XML Parsing

I want to fetch Google news data by XML parsing and save it into an array. The XML is like this
http://news.google.co.in/news?pz=1&cf=all&ned=in&hl=en&output=rss
Well I parse xml some different way than others and being frank I really do not know which technique it is but I assure you it works fine for me and I have implemeted it successfully in so many projects. Have a look at my code where I load tweets from some profile
This is the function where I make call for parser.
-(void)loadtweet
{
#try
{
NSString *urlString = [NSString stringWithFormat:#"https://api.twitter.com/1/statuses/user_timeline.xml?screen_name=SrBachchan&count=5"];
NSLog(#"fetching data from--------> : %#",urlString);
NSString* escapedUrlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSMutableURLRequest *request1 = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:escapedUrlString]];
NSURLConnection *con=[[NSURLConnection alloc] initWithRequest:request1 delegate:self];
if(con)
truckData=[[NSMutableData data]retain];
}
#catch (NSException *exception)
{
UIAlertView *v = [[UIAlertView alloc] initWithTitle:#"ERROR" message:#"Please Try Again Later." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[v show];
[v release];
}
}
And these are the NSURLConnection delegate methods:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[truckData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[truckData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[tweets removeAllObjects];
#try
{
// [app.trucks removeAllObjects];
NSString *thexml=[[NSString alloc] initWithBytes:[truckData mutableBytes] length:[truckData length] encoding:NSUTF8StringEncoding];
NSArray *array=[thexml componentsSeparatedByString:#"<status>"];
NSLog(#"%d",[array count]);
for(int i=1;i<[array count];i++)
{
NSString *str=[array objectAtIndex:i];
NSArray *arr1=[str componentsSeparatedByString:#"<text>"];
NSString *data=[arr1 objectAtIndex:1];
NSRange ranfrom=[data rangeOfString:#"</text>"];
// nt.truckName=[data substringToIndex:ranfrom.location];
[tweets addObject:[data substringToIndex:ranfrom.location]];
}
}
#catch (NSException *exception)
{
UIAlertView *v = [[UIAlertView alloc] initWithTitle:#"ERROR" message:#"Please Try Again Later." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[v show];
[v release];
}
}
I have used some string functions to separate tags and stored the values in Array.
This is where you can start: NSXMLParser class reference.

Asynchronous connection not getting called

I want to create two connections in a single view controller class. I am using NSOperationQueue for this purpose. The two connections are created in two functions and push inside the queue .The problem is delegates are not called. Please help me out. Thanks you in advance
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue=[[NSOperationQueue alloc] init];
NSInvocationOperation *invOperation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(createConnection1) object:nil];
NSInvocationOperation *invOperation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(createConnection2) object:nil];
NSArray *ops=[[NSArray alloc] initWithObjects:invOperation1,invOperation2,nil];
[queue addOperations:ops waitUntilFinished:YES];
}
-(void) createConnection1{
//create connection
NSLog(#"Create Connection 1");
url1 =[[NSMutableString alloc] initWithFormat:#"http://www.google.com/ig/api?weather=New Delhi"];
NSURLRequest *theRequest1=[NSURLRequest requestWithURL:[NSURL URLWithString:url1]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
theConnection1=[[NSURLConnection alloc] initWithRequest:theRequest1 delegate:self];
if (theConnection1) {
connectionCreated1=YES;
receivedData1 = [[NSMutableData data] retain];
NSLog(#"received data 1 %#",receivedData1);
//[theConnection1 setDelegate:self];
}
}
-(void) createConnection2{
//create connection
NSLog(#"Create Connection 2");
url2 =[[NSMutableString alloc] initWithFormat:#"http://www.google.com/ig/api?weather=Chennai"];
NSURLRequest *theRequest2=[NSURLRequest requestWithURL:[NSURL URLWithString:url2]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
theConnection2=[[NSURLConnection alloc] initWithRequest:theRequest2 delegate:self];
if (theConnection2) {
connectionCreated2=YES;
receivedData2 = [[NSMutableData data] retain];
//[theConnection2 setDelegate:self];
NSLog(#"received data 2 %#",receivedData2);
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
if (connectionCreated1==YES) {
[receivedData1 setLength:0];
}
else if (connectionCreated2==YES) {
[receivedData2 setLength:0];
}
else {
NSLog(#"did not receive response");
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
if (connectionCreated1==YES) {
[theConnection1 release];
xmlParser1 = [[NSXMLParser alloc] initWithData:receivedData1];
[xmlParser1 setDelegate:self];
[xmlParser1 parse];
}
else if(connectionCreated2==YES){
[theConnection2 release];
xmlParser2 = [[NSXMLParser alloc] initWithData:receivedData2];
[xmlParser2 setDelegate:self];
[xmlParser2 parse];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"connection failed" message:#"" delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil];
[alert show];
[alert release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if (connectionCreated1==YES) {
[receivedData1 appendData:data];
}
else if(connectionCreated2==YES) {
[receivedData2 appendData:data];
}
else {
NSLog(#"data not received");
}
}
The URL you have given in the first link seems to be borken ... look at this "http://www.google.com/ig/api?weather=New Delhi".. there is space between new delhi. try this instead http://www.google.com/ig/api?weather=New+Delhi

[CFDictionary count]: message sent to deallocated instance

My app is calling the rqst_run method below in didViewLoad method but I've an error. Debugger reports the following error:
[CFDictionary count]: message sent to deallocated instance
and debug marker is placed on this line (in tableView numberOfRowsInSection method below):
if([self.listing_items count] > 0)
I don't know where this variable get released
Declared in header file (interface section):
NSMutableString *rqst_error;
NSMutableData *rqst_data;
NSMutableDictionary *listing_items;
and I defined this method in implementation:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if([self.listing_items count] > 0)
{
if([self.listing_items objectForKey:#"items"])
{
return [[self.listing_items objectForKey:#"items"] count];
}
}
}
- (void)rqst_run
{
rqst_data = [[NSMutableData data] retain];
NSMutableURLRequest *http_request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.feedserver.com/request/"]];
[http_request setHTTPMethod:#"POST"];
NSString *post_data = [[NSString alloc] initwithFormat:#"param1=%#&param2=%#&param3=%#",rqst_param1,rqst_param2,rqst_param3];
[http_request setHTTPBody:[post_data dataUsingEncoding:NSUTF8StringEncoding]];
rqst_finished = NO;
[post_data release];
NSURLConnection *http_connection = [[NSURLConnection alloc] initWithRequest:http_request];
[http_request release];
if(http_connection)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
if([rqst_data length]>0)
{
NSString *rqst_data_str = [[NSString alloc] rqst_data encoding:NSUTF8StringEncoding];
SBJsonParser *json_parser = [[SBJsonParse alloc] init];
id feed = [json_parser objectWithString:rqst_data_str error:nil];
listing_items = (NSMutableDictionary *)feed;
[json_parser release];
[rqst_data_str release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Feed" message:#"No data returned" delegate:self cancemButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Connection Problem" message:#"Connection to server failed" delegate:self cancemButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[rqst_data setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[rqst_data appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[rqst_data release];
[connection release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[rqst_data release];
[connection release];
rqst_finished = YES;
}
NSMutableDictionary must be properly initialized before use. In your code you assign feed to listing_items and then release it. It haven't been retained so listing_items is also removed.
Try to init dictionary like this:
listing_items = [[NSMutableDictionary alloc] initWithDictionary:feed];
and all should work fine.
Instead of this
listing_items = (NSMutableDictionary *)feed;
Use this
self.listing_items = [NSMutableDictionary dictionaryWithDictionary:feed];
It's pretty clear that:
* You use the instance variable instead of the property to assign the value to listing_items
* You put an autoreleased value in this ivar.
listing_items = (NSMutableDictionary *)feed; is clearly your error because feed is an autorleased variable (and then will be deallocated at the end of the current runloop by definition.
Either declare a #property(retain) for listing_items and use it each time you want to assign (autoreleased) value to it (so that the property will manage the retain/release on assignation)
Or retain the stored value manually (but this is painful as you need not to forget to release the previous value before assigning a new one to listing_items each time... which is what the setter method does when called either directly or thru the property assignment)
i think you need to initialize your NSMutableDictionary. Right now its just a pointer pointing to feed. when feed gets released, it just points to nil.
in the viewDidLoad :
listing_items = [[NSMutableDictionary alloc] init];
or you need to retain the data:
listing_items = [(NSMutableDictionary *)feed retain];
SBJsonParser *json_parser = [[SBJsonParse alloc] init];
id feed = [json_parser objectWithString:rqst_data_str error:nil];
listing_items = (NSMutableDictionary *)feed;
[json_parser release];
When you release the json_parser, the dictionary it holds is released too.
So, as others said, you need to retain the dictionary obtained from json_parser.

[NSMutableURLRequest released]: message sent to deallocated instance

My app is calling the rqst_run method below in didViewLoad method but I've an error. Debugger reports the following error:
[NSMutableURLRequest released]: message sent to deallocated instance
I don't know where this variable get released
Declared in header file (interface section):
NSMutableString *rqst_error;
NSMutableData *rqst_data;
NSMutableDictionary *listing_items;
and I defined this method in implementation:
- (void)rqst_run
{
rqst_data = [[NSMutableData data] retain];
NSMutableURLRequest *http_request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.feedserver.com/request/"]];
[http_request setHTTPMethod:#"POST"];
NSString *post_data = [[NSString alloc] initwithFormat:#"param1=%#&param2=%#&param3=%#",rqst_param1,rqst_param2,rqst_param3];
[http_request setHTTPBody:[post_data dataUsingEncoding:NSUTF8StringEncoding]];
rqst_finished = NO;
[post_data release];
NSURLConnection *http_connection = [[NSURLConnection alloc] initWithRequest:http_request];
[http_request release];
if(http_connection)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
if([rqst_data length]>0)
{
NSString *rqst_data_str = [[NSString alloc] rqst_data encoding:NSUTF8StringEncoding];
SBJsonParser *json_parser = [[SBJsonParse alloc] init];
id feed = [json_parser objectWithString:rqst_data_str error:nil];
listing_items = (NSMutableDictionary *)feed;
[json_parser release];
[rqst_data_str release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Feed" message:#"No data returned" delegate:self cancemButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Connection Problem" message:#"Connection to server failed" delegate:self cancemButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[rqst_data setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[rqst_data appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[rqst_data release];
[connection release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[rqst_data release];
[connection release];
rqst_finished = YES;
}
Your initialization
NSMutableURLRequest *http_request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.feedserver.com/request/"]];
is a convenience constructor that has a built-in autorelease for the object you are initializing using the constructor. So by calling
[http_request release];
you are trying to release something that is auto-released. In other words, you are over-releasing.
You should only call release on objects that you allocate using the keywords,
"New", "Alloc", "Copy". or use "retain"
Line [http_request release]; is unnecessary as your object is autoreleased.
For creation of your NSMutableURLRequest you used method which returns aurora eased instance and you not responsible for it's release. If you use methods which require you perform -alloc, -copy, -retain than you responsible for releasing this instance.

NSArray with multiple nested requests

I have an app that uses a segmentedControl. First item is an "All" item, where the rest is created from an array based on result from webservice. When "All" is selected I want to request all the request.
How can I go about this,
NSArray *urls = [NSArray arrayWithObjects:#"http://service/group/1/",
#"http://service/group/2/", nil];
I want to collect all result from the calls into a collection and display it in a UITableView when the "All" item is selected and probably in viewDidLoad.
For the other segments only one of the request is issued and callback with an array that then is used in:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
I have tried to look at this example for making the request from the array MultipleDownloads
Thanks,
The method in my viewController to initiate the multiple download:
- (void)requestChildrenInBackground {
queue = [[NSOperationQueue alloc] init];
//Todo remove hard coded and get from previous request respons
NSArray *urls = [NSArray arrayWithObjects: #"http://service/1/children",
#"http://service/2/children",
#"http://service/3/children", nil];
NSLog(#"%#", urls);
for (NSString * url in urls)
{
GetSchedule *operation =
[GetSchedule urlDownloaderWithUrlString:url];
[queue addOperation:operation];
}
}
This is how the multiple request gets handled:
#import "GetSchedule.h"
#import "JSON.h"
#import "Authentication.h"
#import "AttendanceReportViewController.h"
#interface GetSchedule ()
- (void)finish;
#end
#implementation GetSchedule
#synthesize appDelegate;
#synthesize username;
#synthesize password;
#synthesize authenticationString;
#synthesize encodedLoginData;
#synthesize schedulesArray;
#synthesize url = _url;
#synthesize statusCode = _statusCode;
#synthesize data = _data;
#synthesize error = _error;
#synthesize isExecuting = _isExecuting;
#synthesize isFinished = _isFinished;
+ (id)urlDownloaderWithUrlString:(NSString *)urlString {
NSURL * url = [NSURL URLWithString:urlString];
GetSchedule *operation = [[self alloc] initWithUrl:url];
return [operation autorelease];
}
- (id)initWithUrl:(NSURL *)url {
self = [super init];
if (self == nil)
return nil;
_url = [url copy];
_isExecuting = NO;
_isFinished = NO;
return self;
}
- (void)dealloc
{
[username release];
[password release];
[encodedLoginData release];
[_url release];
[_connection release];
[_data release];
[_error release];
[super dealloc];
}
- (BOOL)isConcurrent
{
return YES;
}
- (void)start
{
if (![NSThread isMainThread])
{
[self performSelectorOnMainThread:#selector(start) withObject:nil waitUntilDone:NO];
return;
}
self.username = appDelegate.username;
self.password = appDelegate.password;
Authentication *auth = [[Authentication alloc] init];
authenticationString = (NSMutableString*)[#"" stringByAppendingFormat:#"%#:%#", username, password];
self.encodedLoginData = [auth encodedAuthentication:authenticationString];
[auth release];
NSLog(#"operation for <%#> started.", _url);
[self willChangeValueForKey:#"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:#"isExecuting"];
// Setup up the request with the url
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:_url];
[request setHTTPMethod:#"GET"];
[request setValue:[NSString stringWithFormat:#"Basic %#", encodedLoginData] forHTTPHeaderField:#"Authorization"];
_connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
if (_connection == nil)
[self finish];
else {
_data = [[NSMutableData alloc] init];
}
}
- (void)finish
{
NSLog(#"operation for <%#> finished. "
#"status code: %d, error: %#, data size: %u",
_url, _statusCode, _error, [_data length]);
[_connection release];
_connection = nil;
[self willChangeValueForKey:#"isExecuting"];
[self willChangeValueForKey:#"isFinished"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
#pragma mark -
#pragma mark NSURLConnection delegate
- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response
{
//[_data release];
//_data = [[NSMutableData alloc] init];
[_data setLength:0];
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
_statusCode = [httpResponse statusCode];
}
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data
{
[_data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Parse the responseData of json objects retrieved from the service
SBJSON *parser = [[SBJSON alloc] init];
NSString *jsonString = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding];
NSDictionary *jsonData = [parser objectWithString:jsonString error:nil];
NSMutableArray *array = [jsonData objectForKey:#"Children"];
schedulesArray = [NSMutableArray array];
[schedulesArray addObject:array];
// Callback to AttendanceReportViewController that the responseData finished loading
[attendanceReportViewController loadSchedule];
[self finish];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
_error = [error copy];
[self finish];
}
#end
When all data is received I want to call back to my ViewController and get an array with all data from all request made.
Create a downloader
Create a downloader class using NSURLConnection.
Keep a member variable called downloaderObjectId.
Write a delegate method for this object. This method will pass the downloaded data and downloaderObjectId back to the delegate.
In the delegate.
Create multiple downloader objects(As per your ncessity) with unique value for the downloaderObjectId.
Store these objects in a NSMutableDictionary
Key for each object will be downloaderObjectId. so that when the delegate method is called after download you take the exact object back from the NSMutableDictionary using this key.
Main point.
Each time delegate is called. You should remove the object from dictionary(The object who is done with the download and called his delgate. You can identify this object by the key downloaderObjectId he holds. )
Then check the count of dictionary. If it is zero you can make sure that your downloads are completed. So you can call your viewcontroller.