iOS: Crash after writing socket

Stella

In my application, I am sending screenshot of the current view programmatically and sending to a socket server program at every 5 seconds interval.

Socket program is running in Eclipse. I checked the code earlier and able to send screenshot of the image to the socket without any issues.

After that, as per my actual requirement, I added a tab bar controller (5 tabs) and used navigation controller for the first tab selection. As per my code below, the first tab bar item is “MyHomeViewController”.

In the “MyHomeViewController” i have a button action called -(IBAction)goAhead:(id)sender. Clicking on this will take to another “HomeViewController”.

In this “HomeViewController”, I connect socket and if the socket connection is success, under “NSStreamEventHasSpaceAvailable” delegate method, i call a function called “[self coShareScreen];” to take to sending screenshot images of the current view (whatever view controller is present) and sending to that socket server program.

I use a “CobrowseSingletonSocket” class, where i have socket related variables and sending screenshot programmatically are handled in this function “-(void) takeScreenshotSend :(NSString *) endOrCancelString”.

My issue is, socket is getting connected successfully now. It should send screenshot of the image programmatically wherever the view I’m currently in. As expected, Its start sending the screenshot of the view programmatically to socket server successfully at every 5 seconds interval.

But,

As its a navigation controller based view, If i coming back to the first view manually, which is “MyHomeViewController”. It tries to send that screen also, but it crashes after immediately write socket is done.

It is crashing immediately after writing here-> “int num = [self.outputStream write:[data bytes] maxLength:([data length])];”

This is crash is happening only if i come back in navigation controller manually. If i stay in “HomeViewController” itself after socket connection, it keeps sending screenshot programmatically a t every 5 seconds interval to socket server without any issues.

I don’t understand what could be the reason here? Please someone advise me, as i’m unable to fix this for long time. Please also let me know if i need to paste any more code here.

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];

    UITabBarController *tabbarCtrler = [[UITabBarController alloc]init];

    MyHomeViewController *myHomeCtrler = [[MyHomeViewController alloc] initWithNibName:@"MyHomeViewController" bundle:NULL];
    [myHomeCtrler.tabBarItem setTitle:@"My Home"];

    ProductsViewController *prodViewCtrler = [[ProductsViewController alloc] initWithNibName:@"ProductsViewController" bundle:NULL];
    [prodViewCtrler.tabBarItem setTitle:@"Products"];

    InboxViewController *inboxViewCtrler = [[InboxViewController alloc] initWithNibName:@"InboxViewController" bundle:NULL];
    [inboxViewCtrler.tabBarItem setTitle:@"Inbox"];

    ContactUSViewController *contactViewCtrler = [[ContactUSViewController alloc] initWithNibName:@"ContactUSViewController" bundle:NULL];
    [contactViewCtrler.tabBarItem setTitle:@"Contact Us"];

    VoiceViewController *voiceViewCtrler = [[VoiceViewController alloc] initWithNibName:@"VoiceViewController" bundle:NULL];
    [voiceViewCtrler.tabBarItem setTitle:@"Voice"];

    UINavigationController *navigationcontroller = [[UINavigationController alloc] initWithRootViewController:myHomeCtrler];
    navigationcontroller.title = @"My News;

    [navigationcontroller.navigationBar setBackgroundImage:[UIImage imageNamed:@"SettingsTitlebar.png"] forBarMetrics:UIBarMetricsDefault];

    [navigationcontroller setNavigationBarHidden:YES];

    //create an array of all view controllers that will represent the tab at the bottom
    NSArray *arrayViewControllers = [[NSArray alloc] initWithObjects:
                                     navigationcontroller, prodViewCtrler, inboxViewCtrler, contactViewCtrler, voiceViewCtrler, nil];

    [tabbarCtrler setViewControllers:arrayViewControllers];

    [self.window makeKeyAndVisible];

    [self.window setRootViewController:tabbarCtrler];

    return YES;
}

and

#import "MyHomeViewController.h"
#import "SettingsViewController.h"

@interface MyHomeViewController ()

@end

@implementation MyHomeViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(IBAction)goAhead:(id)sender
{
    HomeViewController *homeViewController = [[HomeViewController alloc] initWithNibName:@"HomeViewController" bundle:nil];
    [self.navigationController pushViewController:setttingsViewController animated:YES];
}

and

//  HomeViewController.m
//
//

#import "HomeViewController.h"
#import "AppDelegate.h"
#import "CobrowseSingletonSocket.h"

#import <QuartzCore/QuartzCore.h>
#import <notify.h>

@interface HomeViewController ()

@end

@implementation HomeViewController
@synthesize authTexField;
@synthesize sessionID;
@synthesize sentPing;
@synthesize bScreenOff;
@synthesize responseAlertView;
@synthesize portFld;
@synthesize ipFld;
@synthesize shareScreenTimer;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Do any additional setup after loading the view from its nib.
    authTexField.delegate = self;
    responseAlertView.delegate = self;
    ipFld.delegate = self;
    portFld.delegate = self;
    bScreenOff = NO;
    cobrowseSingletonIns = [CobrowseSingletonSocket sharedCobrowseSocketInstance];
}

-(void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self.navigationController setNavigationBarHidden:NO];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(IBAction)connectShare:(id)sender
{
    // Connect socket freshly here

    [self initSocketConnection];

}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];

    return YES;
}

- (IBAction)backAction:(id)sender
{
    [self dismissModalViewControllerAnimated:YES];
}

#pragma mark Socket Connection

- (void)initSocketConnection
{
    NSString * ipAddrStr = ipFld.text;
    NSString * portStr = portFld.text;


        NSLog(@"IPAddress: %@ ; Port: %@", ipAddrStr, portStr);

        CFReadStreamRef readStream;
        CFWriteStreamRef writeStream;

        NSString *ipaddress = ipAddrStr;

        ipaddress = [ipaddress stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

        NSLog(@"Retrieved socket ip: %@", cobrowseSingletonIns.socketIPAddress);

        CFStreamCreatePairWithSocketToHost(NULL, (__bridge  CFStringRef)ipaddress, 8081, &readStream, &writeStream);

        cobrowseSingletonIns.inputStream = (__bridge_transfer NSInputStream *)readStream;
        cobrowseSingletonIns.outputStream = (__bridge_transfer NSOutputStream *)writeStream;
        [cobrowseSingletonIns.inputStream setDelegate:self];
        [cobrowseSingletonIns.outputStream setDelegate:self];

        [cobrowseSingletonIns.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [cobrowseSingletonIns.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [cobrowseSingletonIns.inputStream open];
        [cobrowseSingletonIns.outputStream open];

}


-(void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
{
    NSString *io;

    if (theStream == cobrowseSingletonIns.inputStream) io = @">>";
    else io = @"<<";

    NSLog(@"Stream space : %d",[cobrowseSingletonIns.outputStream hasSpaceAvailable]);

    NSString *event;
    switch (streamEvent)
    {
        case NSStreamEventNone:
            event = @"NSStreamEventNone";
            //statusText.text =  @"Can not connect to the host!";
            NSLog(@"NSStreamEventNone - Can not connect to the host");
            break;

        case NSStreamEventOpenCompleted:
            event = @"NSStreamEventOpenCompleted";
            //pingButton.hidden = NO;
            //statusText.text = @"Connected";
            NSLog(@"Connected");
            break;

        case NSStreamEventHasBytesAvailable:

            event = @"NSStreamEventHasBytesAvailable";
            NSLog(@"NSStreamEventHasBytesAvailable called");

            if (theStream == cobrowseSingletonIns.inputStream)
            {
                //read data
                //uint8_t buffer[1024];
                uint8_t buffer[2];
                NSMutableData *data=[[NSMutableData alloc] init];

                int len;
                while ([cobrowseSingletonIns.inputStream hasBytesAvailable])
                {
                    len = [cobrowseSingletonIns.inputStream read:buffer maxLength:sizeof(buffer)];

                    if(len)
                    {
                        [data appendBytes:&buffer length:len];
                    }
                    else
                    {
                        NSLog(@"no buffer!");
                    }

                }
                NSString *responseStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                responseStr = [responseStr stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

                //do something with data
                NSLog(@"Server said this-> %@", responseStr);
                NSString *successResponse;
                responseAlertView = [[UIAlertView alloc] init];
                if ( [responseStr isEqualToString:@"SUCCESS"])
                {
                    successResponse = @"Successfully connected! Click OK to starts screen sharing!";
                    responseAlertView.tag = 3;
                    [responseAlertView addButtonWithTitle:@"OK"];
                    [responseAlertView addButtonWithTitle:@"CANCEL"];
                }
                else
                {
                    successResponse = @"There seems to be problem in connecting..Try connecting it again with proper Random Auth ID!";
                    responseAlertView.tag = 4;
                    [responseAlertView addButtonWithTitle:@"OK"];
                }
                responseAlertView.delegate = self;
                [responseAlertView setTitle:@"Cobrowsing"];
                [responseAlertView setMessage:successResponse];

                [responseAlertView show];

            }
            break;

        case NSStreamEventHasSpaceAvailable:
        {
            event = @"NSStreamEventHasSpaceAvailable";

            NSLog(@"space : %d", [cobrowseSingletonIns.outputStream hasSpaceAvailable]);


            if ( !cobrowseSingletonIns.bConnectionEstablished )
            {
                NSLog(@"NSStreamEventHasSpaceAvailable - Connection established, sharing is going to be established!");

                if ( theStream == cobrowseSingletonIns.outputStream && !self.sentPing )
                {
                    if ( [sessionID length]<=0 )
                        sessionID = @"EMPTY";

                    NSLog(@"sessionID : %@", sessionID);
                    NSData* data = [sessionID dataUsingEncoding:NSUTF8StringEncoding];

                    int num = [cobrowseSingletonIns.outputStream write:[data bytes] maxLength:([data length])];
                    if (-1 == num) {
                        NSLog(@"Error writing to stream %@: %@", cobrowseSingletonIns.outputStream, [cobrowseSingletonIns.outputStream streamError]);
                    }else{
                        NSLog(@"Wrote %i bytes to stream %@.", num, cobrowseSingletonIns.outputStream);
                    }
                    sentPing = YES;
                }

            }
            else
            {
                NSLog(@"NSStreamEventHasSpaceAvailable - Connection already established");

                if ( [cobrowseSingletonIns.outputStream hasSpaceAvailable] )
                {
                    [self coShareScreen];
                }
            }
        }
            break;

        case NSStreamEventErrorOccurred:
        {
            event = @"NSStreamEventErrorOccurred";
            NSLog(@"NSStreamEventErrorOccurred - Can not connect to the host");
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Co-browsing" message:@"Connection error, Cannot connect to the host!" delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
            alertView.tag = 5;
            [alertView show];

        }
            break;

        case NSStreamEventEndEncountered:
            event = @"NSStreamEventEndEncountered";
            NSLog(@"NSStreamEventEndEncountered - Connection closed by the server");
            break;

        default:
            event = @"** Unknown";
    }

    NSLog(@"%@ : %@", io, event);
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    int tag = alertView.tag;

    NSLog(@"buttonIndex: %d ; alertView.tag: %d", buttonIndex, tag);

    if ( alertView.tag==3 )
    {
        if ( buttonIndex==0 ) // for OK button
        {
            sentPing = NO;

            cobrowseSingletonIns.bConnectionEstablished = YES;
            [cobrowseSingletonIns shareScreen]; // call just once here, then 5 mins thread caller will be called in hasspaceavailable delegate method.
        }
        else if ( buttonIndex==1 ) // for Cancel button
        {
            NSLog(@"User selected Cancel, just stop the socket connection");
            [cobrowseSingletonIns.outputStream close];
            [cobrowseSingletonIns.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        }

    }
    else if (alertView.tag==4)
    {
        NSLog(@"Problem connecting with socket, just stop the socket connection");
        sentPing = NO;
        [cobrowseSingletonIns.outputStream close];
        [cobrowseSingletonIns.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    }
    else if (alertView.tag==5) // Socket connection closed Abruptly, one of the reasons, user manually locked of the phone. In this case, logout and love to login
    {
        NSLog(@"Socket connection closed Abruptly due to unknown reasons");
    }
}

//-(void) shareScreen :(NSTimer *) timerInfo
-(void) coShareScreen
{
    NSLog(@"coShareScreen called");

    [cobrowseSingletonIns shareScreen];
}

@end

and

//
//  CobrowseSingletonSocket.m
//

#import "CobrowseSingletonSocket.h"
#import "AppDelegate.h"
#import "MyUSAAViewController.h"
#import "USAASettingsViewController.h"
#import "ProductsViewController.h"
#import "InboxViewController.h"
#import "ContactUSViewController.h"
#import "VoiceViewController.h"
#import <QuartzCore/QuartzCore.h>

@implementation CobrowseSingletonSocket

static CobrowseSingletonSocket *sharedCobrowseSocketInstance = nil;

@synthesize loginViewController;
@synthesize outputStream;
@synthesize inputStream;
@synthesize bConnectionEstablished;
@synthesize socketIPAddress;
@synthesize servletIPAddress;
@synthesize servletPort;

+(CobrowseSingletonSocket *) sharedCobrowseSocketInstance
{
    @synchronized ([CobrowseSingletonSocket class])
    {
        if ( !sharedCobrowseSocketInstance )
        {
            sharedCobrowseSocketInstance = [[super allocWithZone:NULL] init];
        }
    }
    return sharedCobrowseSocketInstance;
}


+ (id)allocWithZone:(NSZone *)zone
{
    return [self sharedCobrowseSocketInstance];
}

-(void) takeScreenshotSend :(NSString *) endOrCancelString
{
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
    UIGraphicsBeginImageContext(appDelegate.window.bounds.size);
    [appDelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    NSMutableData *data = [NSMutableData data];
    data = (NSMutableData *) UIImagePNGRepresentation(image);
    //[data writeToFile:@"screenshot.png" atomically:YES];

    NSLog(@"shareScreen [data length] %i: ", [data length]);

    NSData *newData = [endOrCancelString dataUsingEncoding:NSUTF16StringEncoding];
    [data appendData:newData];
    NSLog(@"shareScreen [data length] %i: ", [data length]);

    //sentPing = YES;

    int num = [self.outputStream write:[data bytes] maxLength:([data length])];
    if (-1 == num) {
        NSLog(@"Error writing to stream %@: %@", self.outputStream, [self.outputStream streamError]);

    }else{
        NSLog(@"Wrote %i bytes to stream %@.", num, self.outputStream);
        //[self.outputStream close];
    }

}

-(void) shareScreenAtInterval
{
    NSLog(@"Screen sharing going to happen!");
    [self takeScreenshotSend:@"END"]; // appending END, to detect the same on the server side and get out of reading data loop there.

}

-(void) shareScreen
{
    NSLog(@"shareScreen called!");
    [self performSelector:@selector(shareScreenAtInterval) withObject:nil afterDelay:5.0];
}


-(void) disconnectSocket
{
    NSLog(@"Close the socket connection by user");

    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(shareScreenAtInterval) object: nil];
    //[NSObject cancelPreviousPerformRequestsWithTarget:self];

    // Send Cancel message to socket
    [self takeScreenshotSend:@"CANCEL"]; // appending CANCEL, to detect the same on the server side and get out of reading data loop there.

    [self.outputStream close];
    [self.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    self.outputStream = nil;

    self.bConnectionEstablished = NO;

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Co-browsing" message:@"Screen sharing disconnected!" delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
    [alertView show];

     AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
    [appDelegate.window.rootViewController dismissModalViewControllerAnimated:YES];

}

@end

Crash error in Xcode

Error Log

Paulw11

Your problem is here -

 [cobrowseSingletonIns.inputStream setDelegate:self];
 [cobrowseSingletonIns.outputStream setDelegate:self]

Your HomeViewController sets itself as the delegate for the socket, but once it has been removed from view it will be deallocated, because the delegate property on the streams will be a weak reference.

You need to make sure the socket writing is completed and cleaned up when the view controller is removed. Try setting the delegates to nil in viewWillDisappear.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related