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
.
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]