I want to create common class for checking internet connection also it should notify me when internet changes its status.
I am using AFNetworking for checking internet status.
Here is my code i have tried but it is not working please help where i am making mistake??
CheckInternet is my common class derived from NSObject
CheckInternet.h
#import <Foundation/Foundation.h>
#interface CheckInternet : NSObject
+ (void)startNetworkMonitoring;
+ (BOOL)isInternetConnectionAvailable;
#end
CheckInternet.m
#import "CheckInternet.h"
#import "AFNetworking.h"
#implementation CheckInternet
+ (void)startNetworkMonitoring
{
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(#"Reachability: %#", AFStringFromNetworkReachabilityStatus(status));
// Check the reachability status and show an alert if the internet connection is not available
switch (status) {
case -1:
// AFNetworkReachabilityStatusUnknown = -1,
NSLog(#"The reachability status is Unknown");
break;
case 0:
// AFNetworkReachabilityStatusNotReachable = 0
NSLog(#"The reachability status is not reachable");
break;
case 1:
NSLog(#"The reachability status is reachable via wan");
[[NSNotificationCenter defaultCenter] postNotificationName:#"reachabilityChanged" object:nil];
break;
case 2:
// AFNetworkReachabilityStatusReachableViaWiFi = 2
NSLog(#"The reachability status is reachable via WiFi");
[[NSNotificationCenter defaultCenter] postNotificationName:#"reachabilityChanged" object:nil];
break;
default:
break;
}
}];
}
#pragma mark - Check Internet Network Status
+ (BOOL)isInternetConnectionAvailable {
return [AFNetworkReachabilityManager sharedManager].reachable;
}
#end
In My ViewController.m (here i want to check internet status)
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[CheckInternet startNetworkMonitoring];
if ([CheckInternet isInternetConnectionAvailable])
{
NSLog(#"---- Internet YES------ ");
}
else
{
NSLog(#"----- Internet NO------ ");
}
}
//This is not called...
- (void)reachabilityChanged:(NSNotification *)notification
{
NSLog(#"---- reachabilityChanged ----");
}
Thank you in advance!
First, I would recommend to start monitoring your network activity in the AppDelegate. Move [CheckInternet startNetworkMonitoring]; to didFinishLaunchingWithOptions
Second, add the following line to case == 0:
[[NSNotificationCenter defaultCenter] postNotificationName:#"reachabilityChanged" object:[NSNumber numberWithInteger:one]];
Also make sure, you post the status of your connection with the notification. Because it is an integer, you need to wrap it in an object (typically into NSNumber).
Third, you need to observe the reachabilityChanged notification.
Add this in your viewDidLoad.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reachabilityChanged:)
name:#"reachabilityChanged"
object:nil];
In your function - (void)reachabilityChanged:(NSNotification *)notification you should be able to access the notification's userInfo property and read the state code there.
Also, do not forget to unobserve the notification once your viewController has disappeared. So in dealloc
[NSNotificationCenter defaultCenter] removeObserver:self];
Related
Apple developer sample of Reachability cause Memory Leak when turning off wifi during play offline music (using this code) in my app and it got stuck line I mentioned bottom, It may cause by that Player code because log says [__NSCFString reachabilityDidChange:]: unrecognized selector
[[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification object:noteObject];
in this method:
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
{
#pragma unused (target, flags)
NSCAssert(info != NULL, #"info was NULL in ReachabilityCallback");
NSCAssert([(__bridge NSObject*) info isKindOfClass: [CDVReachability class]], #"info was wrong class in ReachabilityCallback");
CDVReachability* noteObject = (__bridge CDVReachability *)info;
// Post a notification to notify the client that the network reachability changed.
[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotificationString object: noteObject];
}
Here is log:
2015-04-12 19:52:03.416 HelloCordova[4094:1250289] -[__NSCFString reachabilityDidChange:]: unrecognized selector sent to instance 0x174232820
And reachabilityDidChange is in this file
#import "ReachabilityManager.h"
#import "Reachability.h"
#interface ReachabilityManager ()
#property NetworkStatus previousReachability;
#end
#implementation ReachabilityManager
- (id) init {
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reachabilityDidChange:)
name:kReachabilityChangedNotification
object:nil];
self.previousReachability = -1;
}
return self;
}
- (void) reachabilityDidChange:(NSNotification *)notification {
NSLog(#"reachabilityDidChange!");
CDVReachability * r = [notification object];
NetworkStatus ns = [r currentReachabilityStatus];
if (self.delegate && [self.delegate respondsToSelector:#selector(reachabilityDidChangeFrom:to:)]) {
[self.delegate reachabilityDidChangeFrom:self.previousReachability to:ns];
}
self.previousReachability = ns;
}
#end
I don't know is that correct but I try this:
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification object:noteObject];
});}
and even this:
// We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
// in case someon uses the Reachability object in a different thread.
#autoreleasepool {
Reachability* noteObject = (__bridge Reachability*)info;
// Post a notification to notify the client that the network reachability changed.
[[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification object:noteObject];
}
I have the following code in my viewController.m class:
- (void) testInternetConnection
{
internetConnection = [Reachability reachabilityWithHostname:#"www.google.com"];
// Internet is reachable
internetConnection.reachableBlock = ^(Reachability*reach)
{
// Update the UI on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Yayyy, we have the interwebs!");
});
};
// Internet is not reachable
internetConnection.unreachableBlock = ^(Reachability*reach)
{
// Update the UI on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Someone broke the internet :(");
});
};
[internetConnection startNotifier];
}
How do I use the startNotifier?
Do I have to put this in every view controller I want to test internet connectivity in?
I use this to test the status:
BOOL status = ([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] != NotReachable);
startNotifier means after that any network state changed will notify whoever register the kReachabilityChangedNotification notification.
You don't have to put this in every view controller.
1、You need a singleton instance and has a member value which is used to keep network state.
2、Register the kReachabilityChangedNotification notification , handle it and get network state and store it in your member value and Post Notification(custom notificaiton) to notify others(your viewcontroller).
3、Provide interfaces to get the current network state so that your viewcontrollers will know the network state when network state changed.
Try this in your app delegate class.
write this code in application didFinishLaunchingWithOptions.
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(reachabilityChanged:) name: kReachabilityChangedNotification object: nil];
Reachability *hostReachable = [[Reachability reachabilityWithHostName: #"www.google.com"] retain];
[hostReachable startNotifier];
Write this methods in your Appdelegate class.
- (void) reachabilityChanged: (NSNotification* )note
{
Reachability* curReach = [note object];
[self updateInterfaceWithReachability: curReach];
}
- (void) updateInterfaceWithReachability: (Reachability*) curReach
{
if(curReach == hostReachable)
{
NetworkStatus netStatus = [curReach currentReachabilityStatus];
if (netStatus == 0 )
{
NSLog(#"offline");
}
else
{
NSLog(#"online");
}
}
}
I've this scenario, UIViewController => UITableViewController => UITableViewController => UIViewController.
From first UITableViewController, I check internet connection and populate data based on that.
This is what the problem is -
1. At first UITableViewController wi-fi is on so data populated from URL,
2. I turn-off wi-fi and select row and go to second UITableViewController, network status is NotReachable and data is populated from database
3. I turn on wi-fi and select row and go to last UIViewcontroller, here network status is NotReachable whereas it should be ReachableViaWiFi
Am I missing something? Please suggest.
-(void) viewWillAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(reachabilityChanged:)
name: kReachabilityChangedNotification
object: nil];
Reachability *reach = [Reachability reachabilityWithHostname: #"www.apple.com"];
[reach startNotifier];
}
- (void) reachabilityChanged: (NSNotification *)notification {
Reachability *reach = [notification object];
if( [reach isKindOfClass: [Reachability class]]) {
NetworkStatus status = [reach currentReachabilityStatus];
switch(status) {
case NotReachable:
{
if (!performedOnce) {
[self processOffline];
performedOnce = YES;
}
[[NSNotificationCenter defaultCenter] removeObserver:self name:kReachabilityChangedNotification object:nil];
}
break;
default:
{
if (!performedOnce) {
[self retrieveUserListWithUrl];
performedOnce = YES;
}
[[NSNotificationCenter defaultCenter] removeObserver:self name:kReachabilityChangedNotification object:nil];
}
break;
}
}
}
I want to trigger an action once the connection is available. There are solutions available which allows manually checking internet connection. One way i find is using NSTimer to check for internet connection during fixed intervals. But is it the most effective way to check for it? if Not, What is the right solution for this?
Here how you can register the observer and listen to it, Your application will be listening to kReachabilityChangedNotification & prompt you whenever status of network changes.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reachabilityHasChanged:) name:kReachabilityChangedNotification object:nil];
internetReachable = [[Reachability reachabilityForInternetConnection] retain];
[internetReachable startNotifier];
-(void) reachabilityHasChanged:(NSNotification *)notice
{
// called after network status changes
NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
switch (internetStatus)
{
case NotReachable:
{
NSLog(#"The internet is down.");
break;
}
case ReachableViaWiFi:
{
NSLog(#"The internet is working via WIFI.");
break;
}
case ReachableViaWWAN:
{
NSLog(#"The internet is working via WWAN.");
break;
}
}
}
Check reachability code provided by apple.In appdelegate.m you can see this method.It will notify the network change.Work on it
//Called by Reachability whenever status changes.
- (void) reachabilityChanged: (NSNotification* )note
{
Reachability* curReach = [note object];
NSParameterAssert([curReach isKindOfClass: [Reachability class]]);
[self updateInterfaceWithReachability: curReach];
}
I try to send local notification. Here some code for class sending the notification:
#interface Sender : UIView
{
NSInteger itemID;
}
#implementation Sender
-(void) changedProperty
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"NotificationName" object:NULL];
}
And here the code to receive this notification:
#interface Listener : UIViewController
{
}
#implementation Listener
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(selectedItem:) name:#"NotificationName" object:NULL];
}
- (void)viewDidUnload
{
[super viewDidUnload];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"NotificationName" object:NULL];
}
-(void) selectedItem:(NSNotification *) notification
{
// some actions
}
But this code doesn't work. Debugging I see how postNotificationName: object works but the method selectedItem: doesn't call
UPDATE.
Here is more code. Maybe this will help.
extern const NSString* selectItemNotificationName;
#interface vRoomSelectorItem : UIView
{
RoomSelectorItemBackground backgroundType;
NSInteger itemID;
}
#property NSInteger itemID;
-(void) setBackgroundType:(RoomSelectorItemBackground) backgroundType;
#interface vRoomSelectorItem ()
#property RoomSelectorItemBackground backgroundType;
#end
#implementation vRoomSelectorItem
const NSString* selectItemNotificationName = #"Reservation.SelectRoom";
-(RoomSelectorItemBackground) backgroundType
{
return backgroundType;
}
-(void) setBackgroundType:(RoomSelectorItemBackground)value
{
if(backgroundType != value)
{
backgroundType = value;
[self changedBackgroundType];
}
}
-(void) changedBackgroundType
{
if(backgroundType == RoomSelectorItemFilled)
{
// animation
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:(NSString*)selectItemNotificationName object:NULL userInfo:[[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInteger:itemID], #"ID", NULL]];
});
}
else
// reverse animation
}
#import "vRoomSelectorItem.h"
#interface vcReservationSelectRoom : UIViewController
{
NSMutableArray* arraySelectorItems;
}
#implementation vcReservationSelectRoom
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(selectedItem:) name:(NSString*)selectItemNotificationName object:NULL];
for(NSInteger i = 1; i <= SELECTOR_ITEM_COUNT; ++i)
{
vRoomSelectorItem* newItem = [[vRoomSelectorItem alloc] initWithFrame:CGRectMake(/*coordinates*/)];
[self.view addSubview:newItem];
[newItem setBackgroundType:RoomSelectorItemTransparent];
[newItem setItemID:i];
[arraySelectorItems addObject:newItem];
newItem = NULL;
}
}
-(void) selectedItem:(NSNotification *) notification
{
// some actions
}
-(void) dealloc
{
arraySelectorItems = NULL;
[[NSNotificationCenter defaultCenter] removeObserver:self name:(NSString*)selectItemNotificationName object:NULL];
}
#end
From your code in the quetion I think you can try this:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(selectedItem:) name:#"NotificationName" object:NULL];
[self.view changedProperty]; // method of your Sender class
}
It seems like your code should work. Make sure the notification is on the main thread and the workflow is as follows:
Add listener to notification center
Initiate sender
Send notification
You can be sure that it is on the main thread with:
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] post...];
});
Couple things I would change:
remove yourself from NSNotificationCenter in -(void)dealloc instead
of -(void)viewDidUnload. viewDidUnload will be deprecated, and
dealloc could get called without viewDidUnload.
For Notifications, I like to store the name in an external constant
to make sure that I don't typo the string:
//header.h
extern NSString *const notificationName;
//implementation.m
NSString *const notificationName = #"notification";
Ok, I've solved the problem. The piece of code above is not enough to understand, why it has not been working. The object of class vcReservationSelectRoom was temporary and it had been destroyed before sending notification from any vRoomSelectorItem. Sorry for my mistake of not showing enough code to solve this problem. And thank you all for helping.