Note that there are some explanatory texts on larger screens.

plurals
  1. POreadInBackgroundAndNotify method not updating until NSTask complete
    primarykey
    data
    text
    <p>I am trying to run a NSTask in a background thread and display its output in a NSTextview that is on a NSPanel attached to my window ( Preference Pane ) using readInBackgroundAndNotify It does not seem like I am receiving the notifications as the method that should be called is not.</p> <p>I have the controller class (PreferencePane.m) init the class (Inventory.m) that is in charge of running the NSTask</p> <pre><code>- (IBAction)updateInventoryButtonPressed:(id)sender { inventory = [[Inventory alloc] init]; .... </code></pre> <p>Then I send it a NSNotification to start the background (from PreferencePane.m):</p> <pre><code>.... [[NSNotificationCenter defaultCenter] postNotificationName:NotificationInventoryRequested object:self]; } </code></pre> <p>This class (Inventory.m) is an observer of this constant (NotificationInventoryRequested) in its init override</p> <pre><code> - (id)init { [super init]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(inventoryRequested:) name:NotificationInventoryRequested object:nil]; return self; } </code></pre> <p>This runs the inventoryRequested method (of Inventory.m)</p> <pre><code>-(void)inventoryRequested:(NSNotification*)aNotification { if (inventoryIsRunning) { NSLog(@"Inventory is already running, ignoring request"); } else { NSLog(@"Starting Inventory in background..."); [NSThread detachNewThreadSelector:@selector(runInventoryTask) toTarget:self withObject:nil]; } } </code></pre> <p>This runs my NSTask method which I have refactored a few times from examples</p> <p>Set a BOOL to help with duplicate runs sanity is handled by inventoryRequested using ivar inventoryIsRunning</p> <pre><code> -(void)runInventoryTask { inventoryIsRunning = YES; .... </code></pre> <p>I double check my task and setup the readInBackgroundAndNotify adding my self as an observer.</p> <pre><code> .... if (task) { NSLog(@"Found existing task...releasing"); [task release]; } task = [[NSTask alloc] init]; NSLog(@"Setting up pipe"); [task setStandardOutput: [NSPipe pipe]]; [task setStandardError: [task standardOutput]]; // Setup our arguments [task setLaunchPath:@"/usr/bin/local/inventory"]; [task setArguments:[NSArray arrayWithObjects:@"--force", nil]]; //Said to help with Xcode now showing logs //[task setStandardInput:[NSPipe pipe]]; [self performSelectorOnMainThread:@selector(addLogText:) withObject:@"Launching Task..." waitUntilDone:false]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(readPipe:) name: NSFileHandleReadCompletionNotification object: [[task standardOutput] fileHandleForReading]]; [[[task standardOutput] fileHandleForReading] readInBackgroundAndNotify]; [task launch]; [task waitUntilExit]; // Let Any Observers know we are finished with Inventory [[NSNotificationCenter defaultCenter] postNotificationName:NotificationInventoryComplete object:self]; inventoryIsRunning = NO; } </code></pre> <p>This all seems to run fine. But this method never gets called (i.e. I don't see the window update or the NSLog in the console ):</p> <pre><code>-(void)readPipe:(NSNotification *)notification { NSData *data; NSString *text; NSLog(@"Read Pipe was called"); data = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem]; if ([data length]){ text = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; // Update the text in our text view [self performSelectorOnMainThread:@selector(addLogText:) withObject:text waitUntilDone:false]; NSLog(@"%@",text); [text release]; } [[notification object] readInBackgroundAndNotify]; } </code></pre> <p>This all seems to run fine. But this method never gets called (i.e. I don't see the window update or the NSLog in the console ). I saw this <a href="https://stackoverflow.com/questions/1324152/nsfilehandle-readinbackgroundandnotify-does-not-work&quot;thread">thread</a> and thought maybe it was my NSPanel blocking the run loop, so I set it as non-modal. I also remember reading about NSNotification's not being synchronous, so I thought perhaps because the method I is being called by a NSNotification, to test I just did this real quick:</p> <pre><code>- (IBAction)updateInventoryButtonPressed:(id)sender { inventory = [[Inventory alloc] init]; /*[[NSNotificationCenter defaultCenter] postNotificationName:NotificationInventoryRequested object:self];*/ [inventory inventoryRequested:self]; [self showPanel:sender]; </code></pre> <p>Obviously self is not valid there, but it served to show me that even calling this method directly did not seem to help ( thus making me think this is not about NSNotification "blocking".)</p> <p>Any thoughts on what I am missing, i have checked for removeObserver anywhere in my code ( I know I need to add it to dealloc and probably in readPipe: when the command run is done). If it helps here is the little NSTextview wrapper which needs work as I does not do line \n in the strings right now.</p> <p>Inventory.h</p> <pre><code>//NSTextview IBOutlet NSTextView * inventoryTextView; </code></pre> <p>Inventory.m</p> <pre><code>-(void)addLogText:(NSString *)text { NSRange myRange = NSMakeRange([[inventoryTextView textStorage] length], 0); [[inventoryTextView textStorage] replaceCharactersInRange:myRange withString:text]; } </code></pre> <p>Any help with this would be appreciated too as its my next stumbling block.</p> <p>UPDATED: Looks like this readData method is being called, however its not updating my Textview until the NSTask is complete,so I have a flow control problem.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload