0

First of all - I am newbie at iOS 6 programming. I am trying to open a socket connection to remote server when application starts, and run it in some background thread. I have a class - NetworkCommunication.h, and 3 view controllers which I would like to be able to read and write to a stream.

The code:

NetworkCommunication.h:

#import <Foundation/Foundation.h>

@interface NetworkCommunication : NSObject {
   NSInputStream* inputStream;
   NSOutputStream* outputStream;
}

@property(retain) NSInputStream *inputStream;
@property(retain) NSOutputStream *outputStream;

-(void) initNetworkCommunication;

@end

NetworkCommunication.m

#import "NetworkCommunication.h"

NSOutputStream *outputStream;
NSInputStream *inputStream;

@implementation NetworkCommunication

@synthesize outputStream;
@synthesize inputStream;

- (id) init {
    NSLog(@"Start!");
    [self initNetworkCommunication];
    return 0;
}

- (void)initNetworkCommunication {
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"127.0.0.1", 7000, &readStream, &writeStream);



inputStream = (__bridge_transfer NSInputStream *)readStream;
outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode ];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];


[inputStream open];
[outputStream open];


[inputStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL
                  forKey:NSStreamSocketSecurityLevelKey];
[outputStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL
                   forKey:NSStreamSocketSecurityLevelKey];

NSDictionary *settings = [[NSDictionary alloc] initWithObjectsAndKeys:
                          [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
                          [NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot,
                          [NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
                          kCFNull,kCFStreamSSLPeerName,
                          nil];

CFReadStreamSetProperty((CFReadStreamRef)inputStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);
CFWriteStreamSetProperty((CFWriteStreamRef)outputStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);

//[outputStream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey];

NSString *response  = @"HELLO from my iphone\n";
NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
[outputStream write:[data bytes] maxLength:[data length]];
}


@end

And I try to start it in any controller or in main.m using: NetworkController *comm = [NetworkController new];

When it reaches this code:

[inputStream open];
[outputStream open];

I got "Thead 1: EXC_BAD_ACCESS (code=1, address=0x10917df0)"

I have no idea how to make it work. I would like to start a thread when the app starts, and to be able to write to the NSOutputStream and read for NSInputStream from any Controller. Is it possible? If so, how?

Thanks in advance

Tomasz Łoś
  • 79
  • 2
  • 10
  • if(!CFWriteStreamOpen(writeStream)) { NSLog(@"Error, writeStream not open"); return; } can you add this code under CFStreamCreatePairWithSocketToHost to check if you connected successfully – meth Mar 29 '13 at 09:47
  • The method itself connects well, the problem is something related with ARC, and memory management I guess – Tomasz Łoś Mar 29 '13 at 10:28
  • https://gist.github.com/thefifthcircuit/446256 here at this address there is a code for connection. it may be helpful to you for debugging. – meth Mar 29 '13 at 10:38
  • @meth thanks, but it still doesn't explain how to access the stream from multiple streams. If I try to create another instance I still get bad access exception and app shut down. – Tomasz Łoś Mar 29 '13 at 11:15

1 Answers1

0

i put your code and tested. i got same error with you when i defined the -(id) init method like you. but after changing like that:

.h of NetworkCommunication

   #import <Foundation/Foundation.h>

    @interface NetworkCommunication : NSObject<NSStreamDelegate>
    {
        NSInputStream* inputStream;
        NSOutputStream* outputStream;
        CFReadStreamRef readStream;
        CFWriteStreamRef writeStream;
    }
    @property(retain) NSInputStream *inputStream;
    @property(retain) NSOutputStream *outputStream;
-(id)init;
    @end

.m of NetworkCommunication

#import "NetworkCommunication.h"

@implementation NetworkCommunication
@synthesize inputStream,outputStream;
-(id)init
{
    self=[super init];
    if (self) {
        NSLog(@"Start!");
        [self initNetworkCommunication];

    }
    return self;//you returned 0 but types not matched.
}
- (void)initNetworkCommunication {



    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"127.0.0.1", 7000, &readStream, &writeStream);



    inputStream = (__bridge_transfer NSInputStream *)readStream;
    outputStream = (__bridge_transfer NSOutputStream *)writeStream;
    [inputStream setDelegate:self];
    [outputStream setDelegate:self];
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode ];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];


    [inputStream open];
    [outputStream open];


 //   [inputStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL
  //                    forKey:NSStreamSocketSecurityLevelKey];
  //  [outputStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL
  //                     forKey:NSStreamSocketSecurityLevelKey];

//    NSDictionary *settings = [[NSDictionary alloc] initWithObjectsAndKeys:
//                              [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
 //                             [NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot,
  //                            [NSNumber numberWithBool:NO], //kCFStreamSSLValidatesCertificateChain,
     //                         kCFNull,kCFStreamSSLPeerName,
    //                          nil];

//    CFReadStreamSetProperty((CFReadStreamRef)inputStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);
//    CFWriteStreamSetProperty((CFWriteStreamRef)outputStream, kCFStreamPropertySSLSettings, (CFTypeRef)settings);

    //[outputStream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey];

    NSString *response  = @"HELLO from my iphone\n";
    NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
    [outputStream write:[data bytes] maxLength:[data length]];
}
@end

in my viewController i create it like that

#import "ViewController.h"
#import "NetworkCommunication.h"
BOOL count;

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
        [super viewDidLoad];

    NetworkCommunication * nc=[[NetworkCommunication alloc] init];  
}

handling events and for seeing errors

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)event {
    NSLog(@"Stream triggered.");
    switch(event) {
            case NSStreamEventErrorOccurred:
        {

            NSLog(@"%@",[stream streamError].localizedDescription);

        }
            break;
        case NSStreamEventHasSpaceAvailable: {
            if(stream == outputStream) {
                NSLog(@"outputStream is ready.");
            }
            break;
        }
        case NSStreamEventHasBytesAvailable: {
            if(stream == inputStream) {
                NSLog(@"inputStream is ready.");
                uint8_t buf[1024];
                unsigned int len = 0;
                len = [inputStream read:buf maxLength:1024];
                if(len > 0) {
                    NSMutableData* data=[[NSMutableData alloc] initWithLength:0];
                    [data appendBytes: (const void *)buf length:len];
                    NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                    [self readIn:s];
                }
            }
            break;
        }
        default: {
            NSLog(@"Stream is sending an Event: %i", event);
            break;
        }
    }
}

- (void)readIn:(NSString *)s {
    NSLog(@"Reading in the following:");
    NSLog(@"%@", s);
}

- (void)writeOut:(NSString *)s {
    uint8_t *buf = (uint8_t *)[s UTF8String];
    [outputStream write:buf maxLength:strlen((char *)buf)];
    NSLog(@"Writing out the following:");
    NSLog(@"%@", s);
}

also when i try with your code. connection refused. so i guess the problem is with your ip address try another one.

meth
  • 1,887
  • 2
  • 18
  • 33
  • Still getting the same error. You are trying to access the object from another controller? – Tomasz Łoś Mar 29 '13 at 11:57
  • How do you create the instance of the class in another controller? – Tomasz Łoś Mar 29 '13 at 12:12
  • NetworkCommunication * nc=[[NetworkCommunication alloc] init]; – meth Mar 29 '13 at 12:26
  • I still get the same error. I agree with you that it's opening the socket, but right after that it crashes the app – Tomasz Łoś Mar 30 '13 at 00:03
  • i think this is about that line [outputStream write:[data bytes] maxLength:[data length]]; – meth Mar 30 '13 at 00:08
  • CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"your_ip_address", 0, &readStream, &writeStream); – meth Mar 30 '13 at 00:33
  • The thing is that when I put the instance creating code in main.m file it works perfectly, however if I put this code to any of controllers it then crashes. And the problem is not about outputStream write opperation, as it crashes when [inputStream open] and [outputStream open] is called. – Tomasz Łoś Mar 30 '13 at 00:41