2

Ok so I am trying to get this app to show network error alert codes. I have added the SystemConfiguration.framework framework and Apple's "Reachability" sample code.

Here is the viewcontroller.h file:

#import <UIKit/UIKit.h>

@class Reachability;

@interface Test_Internet_ConnectionViewController : UIViewController {

    Reachability* internetReachable;
    Reachability* hostReachable;
}

@property BOOL internetActive;
@property BOOL hostActive;

- (void) checkNetworkStatus:(NSNotification *)notice;

@end

Here is the viewcontroller.m file:

#import "Test_Internet_ConnectionViewController.h"
#import "Reachability.h";

@implementation Test_Internet_ConnectionViewController

@synthesize internetActive;
@synthesize hostActive;

/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

        // check for internet connection
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkNetworkStatus:) name:kReachabilityChangedNotification object:nil];

        internetReachable = [[Reachability reachabilityForInternetConnection] retain];
        [internetReachable startNotifier];

        // check if a pathway to a random host exists
        hostReachable = [[Reachability reachabilityWithHostName: @"www.apple.com"] retain];
        [hostReachable startNotifier];

        // now patiently wait for the notification
    }

/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void) checkNetworkStatus:(NSNotification *)notice
{
    // called after network status changes

    NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
    switch (internetStatus)

    {
        case NotReachable:
        {
            NSLog(@"The internet is down.");
            self.internetActive = NO;

            UIAlertView *errorView = [[UIAlertView alloc] initWithTitle:@"Internet Unavailable" message:@"This page cannot load, please check your internet connection and try again." delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];
            [errorView show];
            [errorView release];

            break;

        }
        case ReachableViaWiFi:
        {
            NSLog(@"The internet is working via WIFI.");
            self.internetActive = YES;

            break;

        }
        case ReachableViaWWAN:
        {
            NSLog(@"The internet is working via WWAN.");
            self.internetActive = YES;

            break;

        }
    }

    NetworkStatus hostStatus = [hostReachable currentReachabilityStatus];
    switch (hostStatus)

    {
        case NotReachable:
        {
            NSLog(@"A gateway to the host server is down.");
            self.hostActive = NO;

            break;

        }
        case ReachableViaWiFi:
        {
            NSLog(@"A gateway to the host server is working via WIFI.");
            self.hostActive = YES;

            break;

        }
        case ReachableViaWWAN:
        {
            NSLog(@"A gateway to the host server is working via WWAN.");
            self.hostActive = YES;

            break;

        }
    }
}

- (void)dealloc {
    [super dealloc];

        [[NSNotificationCenter defaultCenter] removeObserver:self];

    }

@end

If there is no internet upon opening the app the error works as intended, but if the app loses connection after the it has initially opened with an internet connection the error displays 3 times, when I obviously only want it to display once.

I think it may be something in the Reachability class where it sends the notification 3 times, maybe in 3 different places. I don't know why it does this, but I think the solution may be to remove the two calls I don't want from the Reachability class but I don't know how.

Can anyone help me, please? Thanks in advance.

EDIT:

The 8 warnings and 4 errors are as follows:

'TestViewController' may not respond to '+checkConnectivity'

Initialization makes integer from pointer without a cast

Local declaration of 'connectivity' hides instance variable

'MyReachability' undeclared

'reachability' undeclared

'TestViewController' may not respond to '-siteAvailable'

'TestViewController' may not respond to '-addConnectivityView'

Redefinition of '-[TestViewController reachabilityChanged:]'

'MyReachability' undeclared

TestViewController may not respond to '-siteAvailable'

TestViewController may not respond to '-addConnectivityView'

TestViewController may not respond to '-removeConnectivityView'

Community
  • 1
  • 1
Baccalad
  • 327
  • 6
  • 19
  • 2
    Is there a reason you're asking the (exact?) same question over and over? http://stackoverflow.com/questions/4769731/xcode-how-to-implement-network-error-alerts-into-my-app http://stackoverflow.com/questions/4821710/trying-to-get-network-error-alert-to-show-on-iphone-app-properly http://stackoverflow.com/questions/4819112/trying-to-implement-network-error-alerts-into-my-app http://stackoverflow.com/questions/4810329/trying-to-get-network-error-alert-to-show-on-iphone-app http://stackoverflow.com/questions/4773711/xcode-adding-network-error-alert-code-into-my-app – Daniel Dickison Jan 27 '11 at 20:56
  • If you read the question correctly (not the title itself) you will find that ultimately the final question at the bottom of my main body of text is slightly different. The last questions I asked have been answered to a certain extent and the question have moved on, to become more developed. – Baccalad Jan 27 '11 at 21:00
  • Further more, on my previous questions that are similarly worded, some very kind and helpful people have answered and I have commented a reply to their answer to delve deeper into my problem and they have no replied. – Baccalad Jan 27 '11 at 21:02
  • Where is `[[NSNotificationCenter defaultCenter] postNotificationName:@"kReachabilityChangedNotification" object: nil];` located? Please show all the code... – aqua Jan 27 '11 at 21:05
  • It is in Apples Reliability.m code, I could post it if you want? – Baccalad Jan 27 '11 at 21:10
  • I don't mean to be rude, but just like in all my other questions, it's been 25 minutes and neither you have replied yet, can I expect one? – Baccalad Jan 27 '11 at 21:30
  • @Baccalad hey, don't worry about them. But, could you please try to narrow down your questions and code next time? Dumping a ton of code in your question makes it harder to answer. If you're looking for code review, we have [a sister site for that](http://codereview.stackexchange.com/). –  Jan 28 '11 at 12:59
  • @Will thanks for the advice, it's just that sometimes I don't know what part of the code to post, but yes, next time I will try and be more concise with my code snippets. – Baccalad Jan 28 '11 at 13:01
  • checkConnectivity should be in your subclass of Reachability. MyReachability is an example name of this subclass. I wrote you exactly what to put in your application delegate and what to put in your view controller. – Nava Carmon Jan 29 '11 at 19:38
  • @Nava Carmon Thanks very much for your help I have now narrowed it down to 1 error and 14 warnings. But still 1 error isn't all that bad. Can I also ask how do I add checkConnectivity to my reachability subclass? Really thanks very much for all your help again. Everyone on this website is usually very helpful :) – Baccalad Jan 29 '11 at 19:59
  • @Nava Carmon I have now, after some time, managed to get the app running without any errors, but there are still a few warnings. They all go along the same lines as something like: "'MyReachability' OR 'TestAppDelegate' may not respond to '---'" I have substituted all manners of terms and can't find a solution. :( – Baccalad Jan 30 '11 at 12:58
  • @Baccalad, names I used are arbitrary, you should put instead names of clsases/functions you use in your applcation. You can post somewhere your project and I can try to help you with these – Nava Carmon Jan 30 '11 at 13:48
  • @Nava Carmon Hi, I have an idea of where to put the code, if you have or know what dropbox is? – Baccalad Feb 05 '11 at 13:19
  • yes, i use it. put it i some shareable area and let me know how to get it – Nava Carmon Feb 05 '11 at 17:57
  • @Nava Carmon Heres the DropBox link: http://dl.dropbox.com/u/19408548/Reachability%20App – Baccalad Feb 05 '11 at 19:22
  • Made it in TextWrangler but for some reason it opens up in TextEdit. You could probably just click open with TextWrangler if you find it easier to use. Thanks for your help :) – Baccalad Feb 05 '11 at 19:24
  • @Nava Carmon Hey have you had any luck? Much appreciated for your help! :) – Baccalad Feb 12 '11 at 15:49
  • sorry just was extremely busy with some release last week... hope to review in a couple of days – Nava Carmon Feb 12 '11 at 16:39
  • please find fixed: http://dl.dropbox.com/u/15211757/Reachability%20App – Nava Carmon Feb 12 '11 at 20:23

2 Answers2

2

Yes, it sends notifications multiple times for some reason. To overcome this I maintained a network status variable in application delegate, which was an observer for kReachabilityChangedNotification. The view was an observer for a custom kViewReachabilityChangedNotification, which was sent by an application delegate when the value actually changed. More than that, after getting a notification from reachability I called a Reachability function on getting a current network status and changed my application delegate variable accordingly. Then I could send a notification to a view to update itself.

This workaround is ugly, but works. I spent plenty of time on understanding why notifications being sent this way and finally gave up finding this solution.

EDIT: Here's your sample - I still don't have a good place to put all working examples, so please try to figure out the solution from the code sample: Subclass Reachability :

@interface MyReachability : Reachability { } +(BOOL) connectedToNetwork; @end

@implementation MyReachability

+ (BOOL) connectedToNetwork {
    // Create zero addy
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;

    // Recover reachability flags
    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
    SCNetworkReachabilityFlags flags;

    BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
    CFRelease(defaultRouteReachability);

    if (!didRetrieveFlags)
    {
        return NO;
    }

    BOOL isReachable = flags & kSCNetworkFlagsReachable;
    BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
    if (needsConnection && (flags & kSCNetworkReachabilityFlagsIsWWAN)) {
        needsConnection = NO;
    }
    return (isReachable && !needsConnection) ? YES : NO;
}

@end In YourApplicationDelegate.h:

@interface YourApplicationDelegate :NSObject
{
     BOOL connectivity;
}
- (void) reachabilityChanged:(NSNotification *) note;
- (BOOL) checkConnectivity;
@end

In YourApplicationDelegate.m add function initReachability call it to init your notifications from Reachability class.

- (void) initReachability
{
    MyReachability * reachability = [ MyReachability sharedReachability ];

    //[ reachability setHostName: [self hostName] ];
    [ reachability setNetworkStatusNotificationsEnabled: YES ];

    [self siteAvailable];

    NSNotificationCenter * notificationCenter = [ NSNotificationCenter defaultCenter ];
    [ notificationCenter addObserver: self
                            selector: @selector( reachabilityChanged: )
                                name: @"kNetworkReachabilityChangedNotification"
                              object: nil ];

    connectivity = [MyReachability testConnection:NO];
    if (!connectivity) {
        if (![MyReachability testConnection:NO]) {
            [self addConnectivityView];
        }
    }
}


- (BOOL) checkConnectivity
{
    return connectivity;
}

- (void) reachabilityChanged:(NSNotification *) note
{
    BOOL    newConnectivity = [MyReachability testConnection:NO];
    if (connectivity != newConnectivity) {
        connectivity = newConnectivity;
        [self siteAvailable];
        if (![MyReachability testConnection:NO]) {
            [self addConnectivityView];
        } else {
            [self removeConnectivityView];
            connectivity = YES;
            [[NSNotificationCenter defaultCenter] postNotificationName:@"kAppNetworkReachabilityChangedNotification" object:nil];
        }
    }
}

Pay attention, that @"kAppNetworkReachabilityChangedNotification" is a custom notification, that your view should subscribe to.

In your view controller's viewDidLoad function:

-(void) viewDidLoad
{
       // your customization
    NSNotificationCenter * notificationCenter = [ NSNotificationCenter defaultCenter ];
    [ notificationCenter addObserver: self
                            selector: @selector( reachabilityChanged: )
                                name: @"kAppNetworkReachabilityChangedNotification"
                              object: nil ];

}


- (void) reachabilityChanged: (NSNotification *) note
{
    BOOL connectivity = [YourAppDelegate checkConnectivity];

    if (connectivity) {
           // update your view accordingly
    } 

}
Nava Carmon
  • 4,523
  • 3
  • 40
  • 74
  • @Nava Carmom Have you had any success? – Baccalad Jan 28 '11 at 17:45
  • your code sample is inside. let me know if you still don't understand something. it should be straight forward – Nava Carmon Jan 29 '11 at 16:54
  • @Nava Carmon Just a couple of quick questions, when you say "subclass Reachability" do you mean the .h or .m file? Also when you say "YourApplicationDelegate" do you mean just that or do you mean the ViewController file? – Baccalad Jan 29 '11 at 18:41
  • @Baccalad, I brought you an example of how did I do it. You should take whatever is suitable for your specific project, customize my code to comply with your source code. YourAppDelegate is your application delegate class, not your view controller. Subclass of Reachability is a subclass of your Reachability class. – Nava Carmon Jan 29 '11 at 19:23
  • Yeah I kinda knew that I am just trying to substitute the correct things. Is difficult though but I'm trying. – Baccalad Jan 29 '11 at 19:27
  • @Nava Carmon Does that mean I have to create subclass of Reachability (subclass of Apples Reachability source code) – Baccalad Jan 29 '11 at 19:36
0
[[NSNotificationCenter defaultCenter] addObserver:self 
                           selector:@selector(handleNetworkChange:) 
                           name:kReachabilityChangedNotification object:nil];

The above line of code should only be called a single time for the entire app. If you invoke this line of code in a function which is called many times, the notification also shows many alerts. So I recommend you to create a singleton class which will live throughout the app and call the above line of code in the area where object for singleton class is created.

Note: the above line of code should be invoked only once for the entire app.

kapex
  • 28,903
  • 6
  • 107
  • 121
jencir
  • 36
  • 2