Listen to Network ON/OFF state in daemon application - Cocoa

67 views Asked by At

I am trying to listen to internet status change using the following code. This works fine with cocoa application but in daemon application, networkChangeHappend method never gets called. Do I need to do anything different for daemon app? Or is there any other alternative to listen to internet state change in daemon application?

main.m

#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SystemConfiguration.h>
#import "ViewController.h"

int main(int argc, const char * argv[])
{
    
    [NSThread detachNewThreadWithBlock:^{
        [[ViewController sharedInstance] startOperation];
    }];

    [[NSRunLoop currentRunLoop] run];
    
    return 0;
}

ViewController.h

#import <Foundation/Foundation.h>

@interface ViewController : NSObject

+ (instancetype _Nonnull )sharedInstance;
- (BOOL)startOperation;

@end

ViewController.m

#import "ViewController.h"
#import <SystemConfiguration/SystemConfiguration.h>
#include <arpa/inet.h>

@implementation ViewController

+ (instancetype)sharedInstance
{
    static ViewController *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[ViewController alloc] init];
    });
    return sharedInstance;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self registerNetworkChangeCallback];
    }
    return self;
}

//MARK: -
- (BOOL)startOperation {
   //some stuff..
}

-(void)registerNetworkChangeCallback
{
    
    struct sockaddr_in zeroAddress;
    
    zeroAddress.sin_addr.s_addr = inet_addr("64.14.192.121");
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;
    
    
    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
    
    void *info = (__bridge void *)(self);
    SCNetworkReachabilitySetCallback ((SCNetworkReachabilityRef)defaultRouteReachability,(SCNetworkReachabilityCallBack)networkChangeHappend,info);

    SCNetworkReachabilityScheduleWithRunLoop (
                                              defaultRouteReachability,
                                              CFRunLoopGetCurrent(),
                                              kCFRunLoopDefaultMode
                                              );
    
    [Logger logString:@"registerNetworkChangeCallback"];
    
}


static void networkChangeHappend(
                                 SCNetworkReachabilityRef target,
                                 SCNetworkReachabilityFlags flags,
                                 void *info
                                 )
{
    BOOL isReachable = flags & kSCNetworkFlagsReachable;
    BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;

    ViewController *viewController = (__bridge ViewController *)info;
    (isReachable && !needsConnection) ? [viewController connected] : [viewController disconnected];
}

-(void)connected {
    [Logger logString:@"Network connected"];
}

-(void)disconnected {
    [Logger logString:@"Network disconnected"];
}

@end
1

There are 1 answers

2
Ol Sen On

You can use your *info pointer to give your callback a way to access the object you placed the Callback in.

void *info = (__bridge void *)(self);
SCNetworkReachabilitySetCallback ((SCNetworkReachabilityRef)defaultRouteReachability,(SCNetworkReachabilityCallBack)networkChangeHappend,info);

and in your Callback accessing "self" again with.

....
YourClass *yourclass = (__bridge YourClass *)info;
(isReachable && !needsConnection) ? [yourclass connected] : [yourclass disconnected];

where -(void)connected{} and -(void)disconnected{} could be methods of YourControllerClass