Wim De Ridder
Wim De Ridder

Reputation: 21

Objective C - How to wait for the asynchronous call to finish

I am new to developing in iOS. I have searched and tried several ways but the program does not want to wait for the asynchronous call to finish.

When debugging, the function CheckForHost first returns -1 as retVal. This causes the method calling the function to continue. A second later the program gets back into the function CheckForHost setting the correct value into retVal. I also tried with NSCondition but no luck either...

Can someone tell me what I am doing wrong or should do differently? Many thanks for your help!

The code below:

-(int)CheckForHost
{
    InternetActive = -1;
    HostActive = -1;
   dispatch_queue_t myQueue = dispatch_queue_create("my queue", NULL);
    __block int retVal = -1;
    dispatch_async(myQueue, ^{
        [self HostInit];
        dispatch_async(dispatch_get_main_queue(), ^{
            [internetReachable stopNotifier];
            [hostReachable stopNotifier];
            [[NSNotificationCenter defaultCenter] removeObserver:self];
            if (InternetActive == 0) {
                retVal = 0;
            } else if (HostActive == 0) {
                retVal = 1;
            } else
                retVal = 2;
        });
    });
    return retVal;
}

-(void)HostInit
{
    // check for internet connection
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkNetworkStatus:) name:kReachabilityChangedNotification object:nil];
    internetReachable = [Reachability reachabilityForInternetConnection];
    [internetReachable startNotifier];
    // check if a pathway to a random host exists
    hostReachable = [Reachability reachabilityWithHostName:@"www.apple.com"];
    [hostReachable startNotifier];
    // now patiently wait for the notification
}

-(void)checkNetworkStatus:(NSNotification *)notice
{
    // called after network status changes
    NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
    switch (internetStatus)
    {
        case NotReachable:
        {
            NSLog(@"The internet is down.");
            InternetActive = 0;
            break;
        }
        case ReachableViaWiFi:
        {
            NSLog(@"The internet is working via WIFI.");
            InternetActive = 1;
            break;
        }
        case ReachableViaWWAN:
        {
            NSLog(@"The internet is working via WWAN.");
            InternetActive = 1;
            break;
        }
    }
    NetworkStatus hostStatus = [hostReachable currentReachabilityStatus];
    switch (hostStatus)
    {
        case NotReachable:
        {
            NSLog(@"A gateway to the host server is down.");
            HostActive = 0;
            break;
        }
        case ReachableViaWiFi:
        {
            NSLog(@"A gateway to the host server is working via WIFI.");
            HostActive = 1;
            break;
        }
        case ReachableViaWWAN:
        {
            NSLog(@"A gateway to the host server is working via WWAN.");
            HostActive = 1;
            break;
        }
    }
}

Upvotes: 1

Views: 3691

Answers (2)

Gil Sand
Gil Sand

Reputation: 6038

I would use blocks, they're easy and reliable

Here is an example of a function with block :

- (void)checkForHostWithBlock:(void (^)(int myReturnedInt))completion{

 //Our function does stuff here, i'll copy paste some of your code

InternetActive = -1;
    HostActive = -1;
   dispatch_queue_t myQueue = dispatch_queue_create("my queue", NULL);
    __block int retVal = -1;
    dispatch_async(myQueue, ^{
        [self HostInit];
        dispatch_async(dispatch_get_main_queue(), ^{
            [internetReachable stopNotifier];
            [hostReachable stopNotifier];
            [[NSNotificationCenter defaultCenter] removeObserver:self];
            if (InternetActive == 0) {
                retVal = 0;
            } else if (HostActive == 0) {
                retVal = 1;
            } else
                retVal = 2;
            if (completion){
                completion(retVal);
            }
        });
    });
}

There you go.

You call that method like any other method, and you can use auto-complete to make sure you write everything down properly.

[self checkForHostWithBlock:^(int myReturnInt){
   //Executed code when the block is called in checkForHost:
   NSLog(@"Here is my int : %i  !!", myReturnInt);
}];

Note that the block parameter can be nil but you need to make sure you check for it in your method then.

Upvotes: 1

Amin Negm-Awad
Amin Negm-Awad

Reputation: 16660

Well, if you want to wait for the completion of the execution, you should not execute it asynchronously. It is the meaning of asynchrony not to wait.

So, if you want to wait, execute the block synchronously or use a semaphore. (I did not say that it is a good idea to execute is synchronously. I just said, what to do.)

Upvotes: 2

Related Questions