0

So, I managed to get NSTask to read asynchronously from a program, but I did it inside the class of a UIView in my storyboard. (Not an Obj-C expert)

My ideia is: I read the text from the program place it on a UITextView and then when there's more repeat the process via NSNotificationCenter

So far this is my code:

LView.m:

- (void)viewDidLoad
{

    [super viewDidLoad];

    NSPipe *out_pipe = [NSPipe pipe];
    sshoutput = [out_pipe fileHandleForReading];
    [sshoutput readInBackgroundAndNotify];

    utilT = [[NSTask alloc] init];
    [utilT setLaunchPath:@"/usr/bin/utilfc9"];
    [utilT setArguments:[NSArray arrayWithObjects: @"-p", @"-f", @"log.txt", nil]];

    [utilT setStandardOutput: out_pipe];
    [utilT setStandardError: out_pipe];
    [utilT launch];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(readPipe:) name:NSFileHandleReadCompletionNotification object:nil];
}

-(void)readPipe: (NSNotification *)notification
{
    NSData *data;
    NSString *new_input;

    if( [notification object] != sshoutput ) { return };

    data = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
    new_input = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];

    self.log.text = [self.wifilog.text stringByAppendingFormat: @"\n%@", new_input];

    if( utilT ) {
        [sshoutput readInBackgroundAndNotify];
    }
}

LView.h:

#import <UIKit/UIKit.h>
#import "NSTask.h"

NSTask *sshT;
NSFileHandle *sshoutput;

So far it works great, I get the data live without any issues.

But, how can I place this NSTask in a more "global" place like AppDelegate's application didFinishLaunchingWithOptions and then process the data and update multiple views in another classes? I tried and of course I can stuff like log.text = new_input inside AppDelegate because it's from another class, and including it does not solve the problem.

As you might noticed, I'm not interested in sending this to the AppStore. It's an app for myself to use on a jailbroken iPhone. Thank you.

TCB13
  • 3,067
  • 2
  • 39
  • 68

2 Answers2

1

Quick way to do it is

In all of the Views that you want to recieve this same notification add the following

ReceiverView

-(void) viewDidLoad
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(read:)     name:@"ReadTest" object:nil];
}

//read function
-(void) read:(NSNotification*)notification
{ // Do something with the notification }

Now in LView.m

-(void)readPipe: (NSNotification *)notification
{
    NSData *data;
    NSString *new_input;

    if( [notification object] != sshoutput ) { return };

    data = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
    new_input = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];

    self.log.text = [self.wifilog.text stringByAppendingFormat: @"\n%@", new_input];

    if( utilT ) {
        [sshoutput readInBackgroundAndNotify];
    }
    //Add the following
    [[NSNotificationCenter defaultCenter] postNotificationName:@"ReadTest" object:notification]
}
Omar Abdelhafith
  • 21,163
  • 5
  • 52
  • 56
  • It's working I get the notifications, but I've noticed that for this to work I need to open the ReceiverView so `ViewDidLoad` happens. How can I programmatically make this happening? Thanks. – TCB13 Jun 02 '12 at 19:58
  • Move the [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(read:) name:@"ReadTest" object:nil]; to the init{ function, also please dont forget to accept the answer :) – Omar Abdelhafith Jun 02 '12 at 19:59
  • I manage to solve it, by placing `-(void)awakeFromNib { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(read:) name:@"NewData" object:nil]; } ` Thank you for everything! – TCB13 Jun 02 '12 at 20:13
0

Be carefull, new_input is allocated but not released => Memory Leak

Elfoiros
  • 468
  • 1
  • 7
  • 18
  • I'm using automatic reference counting so... no need to release `new_input`. Thank you anyway. – TCB13 Jun 02 '12 at 19:40