Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

igorland

macrumors newbie
Original poster
Mar 4, 2014
24
0
Hello. I have an application with different tabs. Tab Setting has a textfield where a TCP-IP address of the server can be inserted. It also has a switch turning on and off TCP-IP connection. The code is:
Code:
- (IBAction)connectToNetwork:(UISwitch *)sender {
    
    if(self.switchNetworkConnection.on) {
        
        // Connection with the server
        [self initNetworkCommunication];
        
        appDelegate.isConnectionAvailableDelegate = YES;
    }
    
    else {
        // Disconnect from server
        [self closeNetworkCommunication];
        
        appDelegate.isConnectionAvailableDelegate = NO;
    }
    
}


// Initiate network communication.

- (void)initNetworkCommunication {

    // IP Address and port
    NSString *ipAddressString = appDelegate.ipAddressDelegate;
    // Transfer NSString to CFStringRef
    CFStringRef ipAddress = (__bridge CFStringRef)ipAddressString;
    
    UInt32 ipPortInt = [appDelegate.ipPortDelegate intValue];
    
	CFReadStreamRef readStream;
	CFWriteStreamRef writeStream;
	CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)ipAddress, ipPortInt, &readStream, &writeStream);
	
    inputStream = objc_unretainedObject(readStream);
	outputStream = objc_unretainedObject(writeStream);
	[inputStream setDelegate:self];
	[outputStream setDelegate:self];
	[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
	[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
	[inputStream open];
	[outputStream open];
    
    NSLog(@"ACARS communication initiated");
}

// Close network communication.
- (void)closeNetworkCommunication {
    
    [inputStream close];
    [outputStream close];
    [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop]
                           forMode:NSDefaultRunLoopMode];
    [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop]
                            forMode:NSDefaultRunLoopMode];
    [inputStream setDelegate:nil];
    [outputStream setDelegate:nil];
    inputStream = nil;
    outputStream = nil;
    
    NSLog(@"ACARS communication closed");
}

// Stream

- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
    
    NSLog(@"stream event %i", streamEvent);
	
	switch (streamEvent)
    {
        case NSStreamEventNone:
        {
            NSLog(@"NSStreamEventNone");
        }
            break;
			
		case NSStreamEventOpenCompleted:
        {
			NSLog(@"NSStreamEventOpenCompleted");
        }
            break;
            
        case NSStreamEventHasBytesAvailable:
        {
            NSLog(@"NSStreamEventHasBytesAvailable");
            
			if (theStream == inputStream)
            {
				uint8_t buffer[1024];
				int len;
				
				while ([inputStream hasBytesAvailable])
                {
					len = [inputStream read:buffer maxLength:sizeof(buffer)];
					if (len > 0)
                    {
                        NSMutableString *output = [[NSMutableString alloc] initWithBytes:buffer length:len encoding:NSUTF8StringEncoding];
						
                        // Implement a method that reads the message sent from the server
                        [self messageReceived:output];
                    }
				}
            }
            
            appDelegate.isConnectionAvailableDelegate = YES;
            
        }
            break;
            
		case NSStreamEventErrorOccurred:
        {
            NSLog(@"NSStreamEventErrorOccurred");
            //Connection switch back to off
            [self.switchNetworkConnection setOn:NO animated:YES];
            
            // Disconnect from server
            [self closeNetworkCommunication];
            
            // Stop activity indicator
            //[self.activityIndicator stopAnimating];
            
            // Pop-up message that the address is not valid
            UIAlertView* disconnectMsg;
            disconnectMsg = [[UIAlertView alloc] initWithTitle:@"No Connection with Server"
                                                       message:@"No connection."
                                                      delegate:self
                                             cancelButtonTitle:@"OK"
                                             otherButtonTitles:nil, nil];
            [disconnectMsg show];
            
            appDelegate.isConnectionAvailableDelegate = NO;
        }
            break;
			
		case NSStreamEventEndEncountered:
        {
            NSLog(@"NSStreamEventEndEncountered");
            
            [theStream close];
            [theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            theStream = nil;
            appDelegate.isConnectionAvailableDelegate = NO;
        }
            break;
            
        default:
        {
			NSLog(@"Unknown event");
        }
            break;
	}
    
}


// Messages that are received from the server.

- (void) messageReceived:(NSString *)message {
    
    NSLog(@"MAP MESSAGE RECEIVED: %@",message);
}

// Messages that contain the code sent to the server. As a result the server will reply with data

- (void)sendMapMessageToServer {
    NSString *response  = [NSString stringWithFormat:@"MESSAGE_TO_SERVER:"];
	NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
	[outputStream write:[data bytes] maxLength:[data length]];
    
    NSLog(@"MAPPING SECOND MESSAGE SENT");
    
}

In the second ViewPanel, I have another switch that turns on a timer to call the sendMapMessageToServer every 5 seconds:

Code:
- (IBAction)connectToServer:(UISwitch *)sender {
    
    if(self.switchConnection.on) {
        
        // Setting timer at 5 sec by default
        connectionTimer = [NSTimer scheduledTimerWithTimeInterval: 5.0
                                                           target: self
                                                         selector: @selector(loadDataToServer)
                                                         userInfo: nil
                                                          repeats: YES];
    }
    
    else {
        // Stop timer
        [connectionTimer invalidate];
        connectionTimer = nil;
    }
}


-(void) loadDataToServer {
    
    NSLog(@"LOADINGDATATOTHEMAP");
    
    self.settingVC = [[IGASettingsViewController alloc]init];
    
    [self.settingVC sendMapMessageToServer];
}


So, when I do it, I see the message "MAPPING SECOND MESSAGE SENT". So, the method is called, however for some reason, the message is not sent to the server. When I trigger sending the message from the same tab (class) it seems to work, so there should not be any problem with the server.

I am stuck.

Thank you!
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
Your loadDataToServer method creates a new view controller every time before it tries to send the data. I don't think that's what you want. You want to only create a single view controller and then reuse that object.

The sendMapMessageToServer method depends on an output stream and a response that almost certainly don't exist when you first create the view controller.
 

igorland

macrumors newbie
Original poster
Mar 4, 2014
24
0
The sendMapMessageToServer method depends on an output stream and a response that almost certainly don't exist when you first create the view controller.

Thanks, PhoneyDeveloper. But I do not understand why. I turn the connection switch on, so [self initNetworkCommunication] method should be called in the Setting UIViewController, i.e. input and output streams should be open and available. They do not close when I go to another UIViewController, do they?

Thanks!
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
These lines create a new view controller but don't put it into the view hierarchy. That's odd. Does the IGASettingsViewController init method call initNetworkCommunication? If not then the streams for this instance of the view controller aren't open and the sendMapMessageToServer method will fail because of that.

Code:
self.settingVC = [[IGASettingsViewController alloc]init];
    
[self.settingVC sendMapMessageToServer];

(btw, you should only use the name init in real init methods. Instead call that method something like startNetworkCommunications or setupNetworkCommunications.)
 

igorland

macrumors newbie
Original poster
Mar 4, 2014
24
0
PhoneyDeveloper, thanks. It took me a while to try out different methods to come up with the solution. Now I have buttons in both ViewControllers that initiate communication with the server and start streaming. Once the message is sent, the stream is closed, so they do not interfere. I also changed my code for
Code:
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent

The original code that I took from a tutorial has a lot of potential errors in it, as I have been explained. Anyways, the problem has been solved not as I originally intended but satisfactory. Thank you for your help!
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.