3

From my main thread I call a selector using

[self performSelectorInBackground:@selector(startTask) withObject:nil];

This is the method startTask:

-(void)startTask{    
   NSTask *task = [[NSTask alloc] init];
   NSPipe *pipe = [[NSPipe alloc] init];
   NSFileHandle *fh = [pipe fileHandleForReading];

   NSArray *args = [NSArray arrayWithObjects:@"-z",iPAddress, [NSString stringWithFormat:@"%@",portNumber], nil];

   [task setLaunchPath:@"/usr/bin/nc"];
   [task setArguments:args];
   [task setStandardOutput:pipe];

   NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
   [nc removeObserver:self];
   [nc addObserver:self
          selector:@selector(dataReady:)
              name:NSFileHandleReadCompletionNotification
            object:fh];

   [task launch];
   [fh readInBackgroundAndNotify];
}

This should prevent NSTask from blocking the main thread (and the UI). But it doesn't. If I remove

[task launch];

The main thread doesn't get blocked. What am I doing wrong? o_O

(BTW dataReady just handles the data. It's not this method, that blocks...)

EDIT: I just found out, that I am not calling the selector from the main thread. I call it from a separate thread! Unfortunately I have to call it from that thread.

Daniel
  • 1,473
  • 3
  • 33
  • 63
  • Have a look at http://stackoverflow.com/questions/7676508/nstask-blocking-the-main-thread, you're approach seemed to work in that case. – Damien Nov 28 '11 at 15:53
  • Please take a sample of your application while its main thread is blocked and edit your question to include the stack trace of the main thread. – Peter Hosey Nov 29 '11 at 07:54

2 Answers2

3

I don't know if this is the answer to your question, but you do have a fundamental issue:

The docs for readInBackgroundAndNotify say:

You must call this method from a thread that has an active run loop.

You are not doing that because startTask is on its own thread and you are not running a run loop on it.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • It doesn't matter if I remove readInBackgroundAndNotify or not. The problem remains. But you are right. I should also chance that. I edited my question!!! I found out, that I am not calling the selector from the main thread. I call it from a separate thread! – Daniel Nov 28 '11 at 14:38
  • @Daniel: Yes, that's what JeremyP said. – Peter Hosey Nov 29 '11 at 07:54
  • I misunderstood the answer. That is indeed the solution. – Daniel Dec 01 '11 at 15:12
3

I'm not sure what the issue is but I suggest looking into NSOperationQueue.

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^(void) {
   NSTask *task = [[NSTask alloc] init];
   NSPipe *pipe = [[NSPipe alloc] init];
   NSFileHandle *fh = [pipe fileHandleForReading];

   NSArray *args = [NSArray arrayWithObjects:@"-z",iPAddress, [NSString stringWithFormat:@"%@",portNumber], nil];

   [task setLaunchPath:@"/usr/bin/nc"];
   [task setArguments:args];
   [task setStandardOutput:pipe];

   NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
   [nc removeObserver:self];
   [nc addObserver:self
          selector:@selector(dataReady:)
              name:NSFileHandleReadCompletionNotification
            object:fh];

   [task launch];
}];
[queue autorelease];

Lemme know if you have any questions

In the documentation heres some info on NSOperationQueue just if you were wondering:

Operation queues usually provide the threads used to run their operations. In Mac OS X v10.6 and later, operation queues use the libdispatch library (also known as Grand Central Dispatch) to initiate the execution of their operations. As a result, operations are always executed on a separate thread, regardless of whether they are designated as concurrent or non-concurrent operations.

DanZimm
  • 2,528
  • 2
  • 19
  • 27
  • thanks for this answer. Though I recommend to change this one line from "[nc removeObserver:self]" to "[nc removeObserver:self name:NSFileHandleReadCompletionNotification" object:fh]". Otherwise you're running danger to remove this whole instance from all notifications. – auco Sep 19 '13 at 15:27
  • @auco ah fair enough, I usually create a class to deal with all these things for me so the only notifications I get are these notifications. Faulty assumption on my part though – DanZimm Sep 21 '13 at 21:57