Can't get Apple Reachability class to define networking right - iphone

I have a classic Apple reachability class which is not adapted to ARC. It defines the network pretty well but it has some mistake that I can't figure out. I've left the whole class unchanged and in the method of another class, I have implemented the following methods to define the connectivity. Here's my BOOL value that changes whenever the internet is available:
- (BOOL) checkForInternetConnection {
[self checkNetworkStatus:nil];
if (isConnection || is3G) {
return YES;
} else {
return NO;
}
}
And here's the standard Reachability method:
-(void) checkNetworkStatus:(NSNotification *)notice
{
NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
switch (internetStatus)
{
case NotReachable:
{
isConnection = NO;
is3G = NO;
}
case ReachableViaWiFi:
{
isConnection = YES;
is3G = NO;
break;
}
case ReachableViaWWAN:
{
NSLog(#"Connected via 3G");
is3G = YES;
break;
}
}
NetworkStatus hostStatus = [hostReachable currentReachabilityStatus];
switch (hostStatus)
{
case NotReachable:
{
isConnection = NO;
is3G = NO;
NSLog(#"No Network");
break;
}
case ReachableViaWiFi:
{
NSLog(#"Connected via WiFi");
isConnection = YES;
is3G = NO;
break;
}
case ReachableViaWWAN:
{
NSLog(#"Connected via 3G");
is3G = YES;
break;
}
}
}
The problem I'm getting is well seen in the NSLog output I get:
2012-12-24 11:19:41.045 Custom Queue[1723:907] Connected via 3G
2012-12-24 11:19:41.046 Custom Queue[1723:907] No Network
2012-12-24 11:19:41.047 Custom Queue[1723:907] Connected via 3G
2012-12-24 11:19:41.048 Custom Queue[1723:907] No Network
After a few seconds it informs me that all is well:
2012-12-24 11:20:11.101 Custom Queue[1723:907] Connected via 3G
2012-12-24 11:20:11.112 Custom Queue[1723:907] Connected via 3G
2012-12-24 11:20:11.113 Custom Queue[1723:907] Connected via 3G
But due to the fact that it thinks that the host is unreachable and gives me the message that there's no connection, I have another function that fires when the Internet is unavailable.
How do I change it so it sees the Internet connection faster, without that occasional "no network" message?

I ended up using Reachability version from Tony Million.
It's great and easy to use. Moreover, it's ARC and iOS 5 (and up) ready.
You can get it here:
https://github.com/tonymillion/Reachability
Thanks, Tony!

Related

RemoteControlReceivedWithEvent in iOS 7 issue

I am having a hard time trying to figure out why in iOS 7 the remote controls don't work. In iOS 7, in the lock screen or even in the Control Center, the buttons are unresponsive and the funny thing is that it works fine on iOS 6.
Here is the code I use:
- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
if (player.playbackState == MPMusicPlaybackStatePlaying) {
[player pause];
}
else {
[player play];
}
break;
case UIEventSubtypeRemoteControlPreviousTrack:
break;
case UIEventSubtypeRemoteControlNextTrack:
break;
default:
break;
}
}}
This is where I found the information about how to perform this:
https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/Remote-ControlEvents/Remote-ControlEvents.html
Any ideas why this is happening? It works on iOS 6 but not iOS 7.
Thanks
I ran into this same problem and I ended up removing the case statement UIEventSubtypeRemoteControlTogglePlayPause and added case statements UIEventSubtypeRemoteControlPlay and UIEventSubtypeRemoteControlPause individually. I don't have an good explanation for why this changed.
*UPDATE*
I found that UIEventSubtypeRemoteControlTogglePlayPause is called when the user is using their headset to control the player. Just a FYI.
I think its a better solution:
case UIEventSubtypeRemoteControlTogglePlayPause:
case UIEventSubtypeRemoteControlPlay:
case UIEventSubtypeRemoteControlPause:
if (_paused) {
[self play:self];
} else {
[self pause:self];
}
break;

How to identify programmatically which connection is active (WiFi or Ethernet) in Iphone

I have a requirement to identify, which connection is active (WiFi or Ethernet) in Iphone programmatically. If, user is using WiFi then I have to display different view controllers in my app.
Please help.
you can use apple provided Reachability class hear bellow example please check this sample code who provide by apple.
http://developer.apple.com/iphone/library/samplecode/Reachability/index.html
you can use it in your Project like bellow steps:-
included Apple's Reachability.h & .m from their Reachability example.
add the SystemConfiguration framework.
when u use it you just called Bellow method:-
Reachability* wifiReach = [[Reachability reachabilityWithHostName: #"www.apple.com"] retain];
NetworkStatus remoteHostStatus = [wifiReach currentReachabilityStatus];
switch (remoteHostStatus)
{
case NotReachable:
{
NSLog(#"Access Not Available");
break;
}
case ReachableViaWWAN:
{
NSLog(#"Reachable WWAN");
break;
}
case ReachableViaWiFi:
{
NSLog(#"Reachable WiFi");
break;
}
}

UILongPressGestureRecognizer is not working

I am trying to create an app where UIButtons can be draged and dropped when a UILongPressGestureRecognizer gesture is fired. Actually my app is working fine in any iPad. it creates problem in iPhone only and lower than iOS 5.0 menas its work fine in iPhone with iOS 5.0.
UILongPressGestureRecognizer * gesture = [[UILongPressGestureRecognizer alloc] initWithTarget: self action: #selector(moveActionGestureRecognizerStateChanged:)];
gesture.minimumPressDuration = 0.5;
gesture.delegate = self;
[self.dragView addGestureRecognizer: gesture];
[gesture release];
- (void) moveActionGestureRecognizerStateChanged: (UILongPressGestureRecognizer *) recognizer
{
switch ( recognizer.state )
{
default:
case UIGestureRecognizerStateFailed:
{
dragView.alpha=1.0;
[dragView release];
dragView=nil;
break;
}
case UIGestureRecognizerStatePossible:
{
dragView.alpha=0.8;
dragView.frame=CGRectMake(dragView.frame.origin.x, dragView.frame.origin.y, dragView.frame.size.width, dragView.frame.size.height);
}
case UIGestureRecognizerStateCancelled:
{
dragView.alpha=1.0;
[dragView release];
dragView=nil;
break;
}
case UIGestureRecognizerStateEnded:
{
//Set dragView on target position
break;
}
case UIGestureRecognizerStateBegan:
{
//NSLog(#"Began");
dragView.alpha=0.8;
dragView.frame=CGRectMake(dragView.frame.origin.x, dragView.frame.origin.y, dragView.frame.size.width, dragView.frame.size.height);
[self bringSubviewToFront:dragView];
break;
}
case UIGestureRecognizerStateChanged:
{
[self.view bringSubviewToFront:dragView];
CGPoint offset = [recognizer locationInView: self.scrollView];
dragView.frame=CGRectMake(offset.x, offset.y, dragView.frame.size.width, dragView.frame.size.height);
}
break;
}
}
I have 2 devices iPhone 3G with iOS 4.2.1 and iPhone 4 with 5.0. This functionality is working fine in iPhone 4 with iOS 5.0 but its not working properly in iPhone 3g with iOS 4.2.1. Sometimes it working in iPhone 3g but sometimes its not calling delegate methods.
Let me know if you have any solution for that.
Thanks!
Is the delegate method not called at all, or is no case selected? I don't know if this really solves your problem, but you should fix your switch (take a loot at the default case):
switch ( recognizer.state )
{
case someCase:
{
// ...
break;
}
default:
break;
}

Know if iOS device has cellular data capabilities

I have a toggle in my app that's "download on WiFi only". However, that toggle is useless for iPod touch or WiFi-iPads.
Is there a way to know if the device has cellular data capabilities in code? Something that would work in the future would be great too (like if an iPod touch 5th gen with 3G comes out).
Hi you should be able to check if it has the pdp_ip0 interface
#import <ifaddrs.h>
- (bool) hasCellular {
struct ifaddrs * addrs;
const struct ifaddrs * cursor;
bool found = false;
if (getifaddrs(&addrs) == 0) {
cursor = addrs;
while (cursor != NULL) {
NSString *name = [NSString stringWithUTF8String:cursor->ifa_name];
if ([name isEqualToString:#"pdp_ip0"]) {
found = true;
break;
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
return found;
}
This doesn't use any private APIs.
3G by itself seems tough to find. You can find out whether a device can make calls using [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"tel://"]]. You can check whether a device can get to the internet, period (and by which method that can currently happen) using Reachability code:
NetworkStatus currentStatus = [[Reachability reachabilityForInternetConnection]
currentReachabilityStatus];
if(currentStatus == kReachableViaWWAN) // 3G
else if(currentStatus == kReachableViaWifi) // ...wifi
else if(currentStatus == kNotReachable) // no connection currently possible
..but aside from that, I don't think you can check for the existence of a 3G modem in the device.***** If it can't make a call, and doesn't currently have cell data turned on and wifi turned off, you won't be able to find out if it's 3G-capable.
An alternative way (not forward-compatible though, so you probably don't want to do this) is to compare the device's model with an exhaustive list, knowing which ones have 3G modems in them, as shown here.
***** As per bentech's answer, if you want to go digging around with device names (this may stop working with no advance warning if Apple decide to change the 3g interface name), call getifaddrs and check for the pdp_ip0 interface.
Swift 3.0 (UIDevice+Extension) of #bentech's answer
Add this line to your BridgingHeader.h:
#import <ifaddrs.h>
Somewhere else:
extension UIDevice {
/// A Boolean value indicating whether the device has cellular data capabilities (true) or not (false).
var hasCellularCapabilites: Bool {
var addrs: UnsafeMutablePointer<ifaddrs>?
var cursor: UnsafeMutablePointer<ifaddrs>?
defer { freeifaddrs(addrs) }
guard getifaddrs(&addrs) == 0 else { return false }
cursor = addrs
while cursor != nil {
guard
let utf8String = cursor?.pointee.ifa_name,
let name = NSString(utf8String: utf8String),
name == "pdp_ip0"
else {
cursor = cursor?.pointee.ifa_next
continue
}
return true
}
return false
}
}
In iOS 6.1, I've been able to use Core Telephony to successfully check for the presence of cellular baseband capabilities. This works on all iPads I tested: Verizon with service activated and without, AT&T with service currently deactivated, SIM card in and out, and a Wi-Fi-only iPad.
The code I used looks like this:
CTTelephonyNetworkInfo* ctInfo = [[CTTelephonyNetworkInfo alloc] init];
CTCarrier* carrier = ctInfo.subscriberCellularProvider;
self.hasWWANCapability = carrier != nil;
For all the iPads with cellular baseband hardware, carrier is not nil. For the Wi-Fi-only iPad, carrier is nil.
I'd think you should be able to use the CoreTelephony Framework.
It does call out that it is for carriers to use, so I am not sure if it is against TOS to access it.
Carriers can use this information to write applications that provide services only for their own subscribers
One way of doing it is to ask for the users location. When it is as accurate as possibLe, you will know if the device have GPS. All devices that have GPS will have 3G. And those that don't GPS won't have 3G.
Apple provided code here.
https://developer.apple.com/library/ios/samplecode/Reachability/Introduction/Intro.html
You should copy Reachability.h and Reachability.m to your project and import
Reachability.h to your class,then
Reachability *networkReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];
while (networkStatus==NotReachable) {
NSLog(#"not reachable");
//no internet connection
return;
}
while (networkStatus==ReachableViaWWAN) {
NSLog(#" ReachableViaWWAN ");
}
while (networkStatus==ReachableViaWiFi) {
NSLog(#"ReachableViaWiFi");
}
Another way is to extend this: https://github.com/monospacecollective/UIDevice-Hardware/blob/master/UIDevice-Hardware.m with this:
-(bool) hasCellular:(NSString*)modelIdentifier {
if ([modelIdentifier hasPrefix:#"iPhone"]) return YES;
if ([modelIdentifier hasPrefix:#"iPod"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad1,1"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad2,1"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad2,2"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad2,3"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad2,4"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad2,5"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad2,6"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad2,7"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad3,1"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad3,2"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad3,3"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad3,4"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad3,5"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad3,6"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad4,1"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad4,2"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad2,5"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad2,6"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad2,7"]) return YES;
if ([modelIdentifier isEqualToString:#"iPad4,4"]) return NO;
if ([modelIdentifier isEqualToString:#"iPad4,5"]) return YES;
if ([modelIdentifier isEqualToString:#"i386"]) return NO;
if ([modelIdentifier isEqualToString:#"x86_64"]) return NO;
return YES;
}
(Clearly it could be edited down to remove either the NO or YES only depending on which way you want to err in case there is a new model...)

On shake... iOS

So I have an IBAction yesNo that I want to be ran on a shake event. Not all too sure why this is not working. Have followed all the documentation.
-(BOOL)canBecomeFirstResponder
{
return YES;
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (event.subtype == UIEventSubtypeMotionShake)
{
[self yesNo];
}
}
And then the IBAction itself:
- (IBAction)yesNo
{
int rNumber = rand() % 26;
NSUserDefaults *def=[NSUserDefaults standardUserDefaults];
if ([[def objectForKey:#"activeVersion"] isEqualToString:#"0"])
{
switch (rNumber) {
case 0:
result.text = #"Never";
break;
case 1:
result.text = #"If you're lucky...";
break;
case 3:
result.text = #"Think twice";
break;
...
default:
break;
}
}
else if ([[def objectForKey:#"activeVersion"] isEqualToString:#"1"])
{
switch (rNumber) {
case 0:
result.text = #"Never1";
break;
case 1:
result.text = #"If you're lucky...1";
break;
...
case 25:
result.text = #"Very doubtful2";
break;
default:
break;
}
}
else if ([[def objectForKey:#"activeVersion"] isEqualToString:#"3"])
{
switch (rNumber) {
case 0:
result.text = #"Never3";
break;
...
case 25:
result.text = #"Very doubtful3";
break;
default:
break;
}
}
}
Basically what I have is a fortune ball type thing and when the iPhone is shaken I need that IBAction run.
Have you made that view the first responder? I.e. [yourView becomeFirstResponder]; (probably from some viewDidAppear: method).
You might want to check if it actually is the first responder when you shake your device.
When I was switching from defining everything graphically in IB to programmatically inline in Xcode, I forgot to make the view the first responder at all. Here's the code that ultimately fixed it:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self becomeFirstResponder];
NSLog(#"self is first responder %i",[self isFirstResponder]);
}
First thing I would question is whether this should be defined as an IBAction. If you only call it from code then you might want to consider using (void) instead (Simply a style choice).
Secondly, are you sure that the method is actually being called? Throw an NSLog in there to make sure.
Thirdly, are you sure that [def objectForKey:#"activeVersion"] returns a string? Is the value returned what you would expect? Throw an NSLog in there to make sure.
My guess is that one of the NSLogs will give you the answer to your question as the rest of your code seems fine.