Jack Humphries
Jack Humphries

Reputation: 13267

Setting variable with Grand Central Dispatch not retrievable

I'm trying to set and a NSURL using grand central dispatch, however it appears that the variable is set and accessible until you try to access it outside of the grand central dispatch block.

-(void)viewDidLoad {

[super viewDidLoad];

dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(backgroundQueue,^{

    self.ubiquitousURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];

   NSLog(@"ubiq inside: %@", self.ubiquitousURL);

    if (self.ubiquitousURL) {

        self.iCloudDocURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@Documents", self.ubiquitousURL]];
        self.iCloudDocString = [self.iCloudDocURL absoluteString];

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadFiles) name: UIApplicationDidBecomeActiveNotification object:nil];

    } else {

        /* change to the main queue if you want to do something with the UI. For example: */
        dispatch_async(dispatch_get_main_queue(),^{

            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Please enable iCloud" message:nil delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];

            [alert show];

        });

    }

});


NSLog(@"ubiq outside: %@", self.ubiquitousURL);

}

The first NSLog which, starts with ubiq inside returns the correct URL, while ubiq outside returns NULL. I'm using ARC, so no need to mention memory or anything similar... this is a GCD problem.

Do you know why self.ubiquitousURL is not accessible outside of the GCD block? Thanks.

Upvotes: 0

Views: 522

Answers (2)

user523234
user523234

Reputation: 14834

You are making async call. So this line NSLog(@"ubiq outside: %@", self.ubiquitousURL); will get executed whether or not your code inside backgroundQueue is done.

You would see the outside log first then inside log.

Upvotes: 4

Becca Royal-Gordon
Becca Royal-Gordon

Reputation: 17861

dispatch_async means "run this later". Thus, the code inside the block doesn't run immediately; it runs at some later time, after the "outside" NSLog call has already been run. If you were to, for instance, put sleep(5) before the NSLog call, you would probably see the value. (You shouldn't really do that in the actual code, though; it would basically freeze the app for five seconds.)

If you want to run more code on the main queue after you've set that property, do something like this:

dispatch_async(backgroundQueue,^{
    self.ubiquitousURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];

    NSLog(@"ubiq inside: %@", self.ubiquitousURL);

    if (self.ubiquitousURL) {
        self.iCloudDocURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@Documents", self.ubiquitousURL]];
        self.iCloudDocString = [self.iCloudDocURL absoluteString];

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadFiles) name: UIApplicationDidBecomeActiveNotification object:nil];

        // ************** NEW HOTNESS HERE **************
        dispatch_async(dispatch_get_main_queue(),^{
            NSLog(@"ubiq outside: %@", self.ubiquitousURL);
        });
    } else {
        /* change to the main queue if you want to do something with the UI. For example: */
        dispatch_async(dispatch_get_main_queue(),^{
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Please enable iCloud" message:nil delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alert show];
        });
    }
});

Replace that NSLog line with a method call to do actual work if that's what you want to do once you've retrieved the iCloud URL.

Upvotes: 3

Related Questions