iosobjective-cipaddata-synchronizationcellular-network

CTTelephonyNetworkInfo's currentRadioAccessTechnology Ambiguous response


I have a scenario in one of my applications that I should allow the user to sync some data to server only if the connection is at least 4G or LTE. Below is the source code I use and it works fine until the scenario explained below occurs/happens.

if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS]) {
                self.currentCellularDataConnectionType = kGPRS;
                self.cellularConnectionFast = NO;
            }
            else if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyWCDMA]) {
                self.currentCellularDataConnectionType = kWCDMA;
                self.cellularConnectionFast = NO;
            }
            else if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge]) {
                self.currentCellularDataConnectionType = kEDGE;
                self.cellularConnectionFast = NO;
            }
            else if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE]) {
                self.currentCellularDataConnectionType = kLTE;
                self.cellularConnectionFast = YES;
            }
            else if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMA1x]) {
                self.currentCellularDataConnectionType = (NSString *)currentCellularAccessTechnology;
                self.cellularConnectionFast = NO;
            }
            else if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyHSDPA] ||
                     [currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyeHRPD]) {
                self.currentCellularDataConnectionType = [NSString stringWithFormat:@"%@ ~= %@",currentCellularAccessTechnology,k4G];
                self.cellularConnectionFast = YES;
            }
            else if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyHSUPA] ||
                     [currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0] ||
                     [currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA] ||
                     [currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB]) {
                self.currentCellularDataConnectionType = [NSString stringWithFormat:@"%@ ~= %@",currentCellularAccessTechnology,k3G];
                self.cellularConnectionFast = NO;
            }
            else {
                self.currentCellularDataConnectionType = (NSString *)currentCellularAccessTechnology;
                self.cellularConnectionFast = NO;
            }

currentCellularDataConnectionType keeps current radio access technology and cellularConnectFast property determines whether the connection is fast enough.

The issue occurs in the following scenario,

If the user puts the iPad to sleep mode by pressing the sleep/power button the CTRadioAccessTechnologyDidChangeNotification notification sometimes gives the "currentRadioAccessTechnology" property value as NULL or NIL. And there is we won't get a second notification with the correct data connection type (RadioAccessTechnology) after that. So I cannot set the "cellularConnectionFast" property value in that condition.

I tried to implement a logic as to set the "currentCellularDataConnectionType" and "cellularConnectionFast" property values only if the CTTelephonyNetworkInfo.currentRadioAccessTechnology value is not NULL or NIL as given below,

if ((NSNull *)currentCellularAccessTechnology == [NSNull null] || currentCellularAccessTechnology == nil) {
            DDLogInfo(@"From %s, New Cellular Connection Type recieved as: %@, so sticking with the previous Cellular Connection Type: %@",__PRETTY_FUNCTION__,currentCellularAccessTechnology,self.currentCellularDataConnectionType);
        }
        else {
            if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS]) {
                self.currentCellularDataConnectionType = kGPRS;
                self.cellularConnectionFast = NO;
            }
            else if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyWCDMA]) {
                self.currentCellularDataConnectionType = kWCDMA;
                self.cellularConnectionFast = NO;
            }
            else if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge]) {
                self.currentCellularDataConnectionType = kEDGE;
                self.cellularConnectionFast = NO;
            }
            else if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE]) {
                self.currentCellularDataConnectionType = kLTE;
                self.cellularConnectionFast = YES;
            }
            else if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMA1x]) {
                self.currentCellularDataConnectionType = (NSString *)currentCellularAccessTechnology;
                self.cellularConnectionFast = NO;
            }
            else if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyHSDPA] ||
                     [currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyeHRPD]) {
                self.currentCellularDataConnectionType = [NSString stringWithFormat:@"%@ ~= %@",currentCellularAccessTechnology,k4G];
                self.cellularConnectionFast = YES;
            }
            else if ([currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyHSUPA] ||
                     [currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0] ||
                     [currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA] ||
                     [currentCellularAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB]) {
                self.currentCellularDataConnectionType = [NSString stringWithFormat:@"%@ ~= %@",currentCellularAccessTechnology,k3G];
                self.cellularConnectionFast = NO;
            }
            else {
                self.currentCellularDataConnectionType = (NSString *)currentCellularAccessTechnology;
                self.cellularConnectionFast = NO;
            }

However, I saw comment in the Raywenderlich post that there are chances that CTTelephonyNetworkInfo.currentRadioAccessTechnology can return 'nil' when the device is not connected to a radio tower.

What is the implementation I can do in this scenario? I use reachability class to identify the current network type (No connection, WiFi or WWAN) and make the "currentRadioAccessTechnology" value calculation only if WWAN.


Solution

  • I think you are getting an instance of CTTelephonyNetworkInfo, and then calling currentRadioAccessTechnology on that ( it is what I do).

    The problem comes, exactly as you pointed out when the device sleeps. The CTTelephoneNetworkInfo instance keeps working while your app is running in the background, but as soon as you go inactive; it becomes invalid.

    You need to get a fresh instance of CTTelephoneNetworkInfo when you become active again ( respond to notification UIApplicationWillBecomeActive).

    As you pointed out, currentRadioAccessTechnology does return null when you're not connected to a radio tower, but then reachability won't be returning cellular, so you should be OK.

    As a free bonus, the value returned by currentRadioAccessTechnology is a string, so you can clean up all those if statements.

    Set up reference tables in a dispatch once block

    NSSet<NSString*> fastTechs = [[NSSet alloc] initWithObjects: CTRadioAccessTechnologyHSDPA, CTRadioAccessTechnologyHSDPD, CTRadioAccessTechnologyLTE, nil];
    
    NSDictionary<NSString*,NSNumber> accessTechTypes = @{ CTRadioAccessTechnologyHSDPA :k4g, CTRadioAccessTechnologyLTE : kLTE};
    

    Then your regular code looks like :

    CTRadioAcessTechnology accessTech = telephonyInfo.currentRadioAccessTechnology;
    self.cellularConnectionFast = [fastTechs contains:accessTech];
    

    And

    self.currentCellularDataConnectionType = accessTechTypes[accessTech]