George Boot
George Boot

Reputation: 605

How to reconnect when a NSStream loses connection?

I am building an app that monitors the position of the user, and sends it via a socket to our server. On app startup the app connects to the socket on our server, and are we able to send data to the server.

But when the user changes from cell to wifi, or so, the connection drops. I'm trying to figure out how to simply reconnect (automatic), but I can't find out how. Can someone help me?

The code I'm using now (LocationRecorder.m):

//
//  LocationRecorder.m
//

#import "LocationRecorder.h"
#import <Cordova/CDV.h>
#import <coreLocation/CoreLocation.h>
#import <Foundation/Foundation.h>

@implementation LocationRecorder

@synthesize locationManager;

NSInputStream *inputStream;
NSOutputStream *outputStream;

- (void)startUpdates
{
    // this only runs once when the app starts up
    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;

    [locationManager startUpdatingLocation];
    [locationManager startUpdatingHeading];

    // connect to the socket
    [self initNetworkCommunication];

    // set a timer for every 5 seconds
    [NSTimer scheduledTimerWithTimeInterval:5
                                     target:self
                                   selector:@selector(timerInterval:)
                                   userInfo:nil
                                    repeats:YES];
}

- (void)timerInterval:(NSTimer *) timer
{
    CLLocation *location    = [locationManager location];

    // process location data
    [self processLocationData:location];
}

- (void)processLocationData:(CLLocation *)location
{
    // format all the data to prepare it for sending it to the server

    NSString *response  = [NSString stringWithFormat:stringFormat,
                           utctime,
                           utcdate,
                           lat,
                           lng,
                           alt,
                           speed,
                           heading,
                           imei,
                           numsat,
                           battery,
                           cellno];

    //NSLog(@"%@", @"tx");

    NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];

    // check for connection
    if ([outputStream streamStatus] != NSStreamStatusOpen) {
        NSLog(@"%@", @"reconnecting...");
        [outputStream open];
    }
    [outputStream write:[data bytes] maxLength:[data length]];
}

- (void)initNetworkCommunication
{
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;

    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"***.***.***.***", 9000, &readStream, &writeStream);

    outputStream = (NSOutputStream *)writeStream;
    // we don't initialize the inputStream since we don't need one (the server does not (yet) talk back)

    [outputStream setDelegate:self];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outputStream open];
}

- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
{
    switch (streamEvent)
    {
        case NSStreamEventNone:
            // can not connect to host, no event fired
            break;

        case NSStreamEventOpenCompleted:
            // connected!
            NSLog(@"%@", @"connected to socket");
            break;

        case NSStreamEventErrorOccurred:
            // Connection problem
            NSLog(@"%@", @"connection lost");
            [theStream open]; //this does not work :-(
            break;

        case NSStreamEventEndEncountered:
            // connection closed
            [theStream close];
            [theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [theStream release];
            theStream = nil;
            break;

        default:
            // unknown or untracked event
            break;
    }
}

@end

Upvotes: 4

Views: 3822

Answers (1)

George Boot
George Boot

Reputation: 605

Credits to Martin R for his simple solution.

I added [outputStream close] to NSStreamEventErrorOccurred, and before I send data to the socket in processLocationData I added the following code:

// check for connection
if ([outputStream streamStatus] != NSStreamStatusOpen) {
    NSLog(@"reconnecting...", nil);
    [self initNetworkCommunication];
}

Upvotes: 1

Related Questions