I have an iOS app that makes some small network requests on app launch (resource updates, etc). If the user turns off cellular access for the app in iOS Settings, they get a prompt from iOS about network usage every time they launch. Is there a way to know programmatically that cellular data for this app has been disabled, so that I can disable the requests at startup?
-
You can use the reachability classes – Woodstock Mar 21 '14 at 16:09
-
1Reachability does not work for this, it reports incorrectly "reachable". http://stackoverflow.com/questions/26357954/how-to-tell-if-the-user-turned-off-cellular-data-for-my-app – cat Feb 06 '15 at 11:27
7 Answers
So I found this on the apple dev forums from an Apple engineer (https://devforums.apple.com/message/1059332#1059332).
Another developer wrote in to DTS and thus I had a chance to investigate this in depth. Alas, the news is much as I expected: there is no supported way to detect that your app is in this state. Nor is there a way to make a "no user interaction" network connection, that is, request that the connection fail rather than present UI like this. If these limitations are causing problems for your app, I encourage you to file a bug describing your specific requirements.
https://developer.apple.com/bug-reporting/
So it looks like it is not possible to detect if cellular data for your app has been turned off.
Edit
I filed a radar for this requesting that it be added. I just got this notification in my radar
We believe this issue has been addressed in the latest iOS 9 beta.
I looked through the API diffs, but so far I can't find the new API.

- 5,293
- 1
- 23
- 37
-
Darn. Marco Arment seems to have hit the same problem (https://twitter.com/marcoarment/status/528753787033628672 and surrounding tweets). – Tom Hamming Nov 14 '14 at 00:40
-
3The 'fix' that apple did for iOS 9 was to set SCNetworkReachabilityFlags flags to the undefined value of 0 instead of kSCNetworkReachabilityFlagsReachable – Casey Oct 06 '15 at 21:10
-
1This capability is available for iOS9 or later using CTCellularData. – Paul King Jan 09 '18 at 00:58
As of iOS9, the capability to check the setting to enable/disable use of cellular data for your app (Settings/Cellular/AppName) is available using Apple's CTCellularData class. The following code will set cellularDataRestrictedState when it is run initially and then set it and log whenever it changes:
import CoreTelephony
var cellularDataRestrictedState = CTCellularDataRestrictedState.restrictedStateUnknown
let cellState = CTCellularData.init()
cellState.cellularDataRestrictionDidUpdateNotifier = { (dataRestrictedState) in
if cellularDataRestrictedState != .restrictedStateUnknown { // State has changed - log to console
print("cellularDataRestrictedState: " + "\(dataRestrictedState == .restrictedStateUnknown ? "unknown" : dataRestrictedState == .restricted ? "restricted" : "not restricted")")
}
cellularDataRestrictedState = dataRestrictedState
}
Unfortunately (as of iOS11) this seems to check only the state of the app's switch - if your app's switch is set to enabled and the user switches the Cellular Data master switch to disabled, this API will return the app's state as being "not restricted".

- 1,881
- 20
- 23
Just wanted to add an Objective C version of the above Swift code for future travellers.
- (void)monitorCanUseCellularData {
if (GCIsiOS9) {
CTCellularData *cellularData = [[CTCellularData alloc] init];
NSLog(@"%ld", cellularData.restrictedState);
// 0, kCTCellularDataRestrictedStateUnknown
[cellularData setCellularDataRestrictionDidUpdateNotifier:^(CTCellularDataRestrictedState state) {
NSLog(@"%ld", state);
self.canUseCellularData = cellularData.restrictedState ==2?true:false;
}];
}
}

- 5,598
- 9
- 55
- 113
I have found that the CTCellularData
class needs some time to get to the correct value. In my implementation I call the didUpdateNotifier
very early after appDidFinishLaunching
. By the time my networking call are returning with errors I definitely have a correct value for the restricted state.
class CellularRestriction: NSObject {
private static var cellularData = CTCellularData()
private static var currentState = CTCellularDataRestrictedState.restrictedStateUnknown
static var isRestricted: Bool {
currentState = cellularData.restrictedState
return currentState == .restricted
}
static func prepare() {
if currentState == .restrictedStateUnknown {
cellularData.cellularDataRestrictionDidUpdateNotifier = { state in
currentState = cellularData.restrictedState // This value may be inconsistent, however the next read of isRestricted should be correct.
}
}
}
}
You can detect if cellular data disabled using NWPathMonitor class. (https://developer.apple.com/documentation/network/nwpathmonitor)
let cellMonitor = NWPathMonitor(requiredInterfaceType: .cellular)
cellMonitor.pathUpdateHandler = { path in
self.isCellConnected = path.status == .satisfied
}

- 12,813
- 11
- 47
- 64
Adding to dirkgroten's answer, you can use the Apple Reachability class, found here:
https://developer.apple.com/Library/ios/samplecode/Reachability/Introduction/Intro.html
It uses SCNetworkReachability
, and is very straight forward to use, it will detect connectivity via Cell and WiFi as you will need to check both at start up.

- 8,932
- 4
- 43
- 64
-
2This will still report as reachable via WWAN even if the user has disabled cellular data usage for the app. – Scott H Apr 01 '15 at 00:33
There are lots of frameworks out there that will give you the status of your network connectivity, and of course you can roll your own. I've found AFNetworking
to be one of the best. It has a singleton class called AFNetworkReachabilityManager
that abstracts some of the complexities for you. Specifically you'll want to look at the two boolean properties:
reachableViaWWAN
reachableViaWiFi
There is also a reachability changed status block that you can set:
– setReachabilityStatusChangeBlock:

- 7,055
- 2
- 38
- 53
-
3Reachability does not work for this, it reports incorrectly "reachable". http://stackoverflow.com/questions/26357954/how-to-tell-if-the-user-turned-off-cellular-data-for-my-app – cat Feb 06 '15 at 11:32