1
votes

I need to download data from a URL (this prints the data in JSON format) and store it in a "configuration" file for the app in the app's AppDelegate.m file. When I run the app, it simply skips over the dispatch_async code for some reason. Why is this happening and how do I fix this ?

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //Download the config.json file
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSString *configFileUrl = @"http://webserviceurl";
        //NSString *downloadToFile = @"Configuration.json";
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:configFileUrl]];
        [self performSelectorOnMainThread:@selector(writeDataToConfigurationJsonFile:) withObject:data waitUntilDone:YES];
    });

 //More code below

And this is where I am writing the data to a file in the Documents directory of the app:

-(void)writeDataToConfigurationJsonFile:(NSData*)jsonData{

    NSString *content = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

    //get the documents directory:
    NSArray *paths = NSSearchPathForDirectoriesInDomains
    (NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];

    //make a file name to write the data to using the documents directory:
    NSString *fileName = [NSString stringWithFormat:@"%@/Configuration.json", documentsDirectory];

    //save content to the documents directory
    [content writeToFile:fileName
              atomically:YES
                encoding:NSUTF8StringEncoding
                   error:nil];
}
4
take a look at NSURLConnection loading data asynchronously methods that should work for you - Shams Ahmed
It's not skipping over it, it's returning immediately which is exactly what dispatch_async is supposed to do instead of blocking until finished. - iwasrobbed

4 Answers

1
votes

performSelectorOnMainThread is a run loop method, you need to use:

dispatch_async(dispatch_get_main_queue(), ^{/*code*/});
1
votes

You can nest a call to dispatch_sync() within dispatch_async() to ensure after the data is downloaded, the data is written synchronously on the main thread.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //Download the config.json file
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSString *configFileUrl = @"http://webserviceurl";
        //NSString *downloadToFile = @"Configuration.json";
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:configFileUrl]];

        dispatch_sync(dispatch_get_main_queue(), ^{
            [self writeDataToConfigurationJsonFile:data];
        });
    });
}
1
votes

When you're asynchronously dispatching a thread, create a new serial/concurrent queue.

And for the synchronous dispatch, go back to the main queue (try without using 'waitUntilDone:YES'):

    dispatch_async(dispatch_queue_create("com.yourOrgName", DISPATCH_QUEUE_SERIAL), ^{

    NSString *configFileUrl = @"http://webserviceurl";
    //NSString *downloadToFile = @"Configuration.json";
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:configFileUrl]];
    dispatch_sync(dispatch_get_main_queue(), ^ {
    [self performSelector:@selector(writeDataToConfigurationJsonFile:)     withObject:data afterDelay:0.0f];

      });
     });
0
votes

For the purpose of this application, the best way was to use a synchronous request rather than an asynchronous request. Here's the final chunk of code -

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"some url"]];
NSError        *error = nil;
NSURLResponse  *response = nil;
NSData *receivedData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *string = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
NSLog(@"response");

NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

//make a file name to write the data to using the documents directory:
NSString *fileName = [NSString stringWithFormat:@"%@/Configuration.json", documentsDirectory];
//save content to the documents directory

[string writeToFile:fileName
         atomically:YES
           encoding:NSUTF8StringEncoding
              error:nil];