Я пытаюсь запустить NSTask в фоновом потоке и отобразить его вывод в NSTextview, который находится на NSPanel, присоединенном к моему окну (Панель настроек), с использованием readInBackgroundAndNotify. Не похоже, что я получаю уведомления как метод, которыйдолжен быть вызван не.
У меня есть класс контроллера (PreferencePane.m) init класс (Inventory.m), который отвечает за запуск NSTask
- (IBAction)updateInventoryButtonPressed:(id)sender
{
inventory = [[Inventory alloc] init];
....
Затем я отправляюэто NSNotification для запуска фона (из PreferencePane.m):
....
[[NSNotificationCenter defaultCenter]
postNotificationName:NotificationInventoryRequested
object:self];
}
Этот класс (Inventory.m) является наблюдателем этой константы (NotificationInventoryRequested) в переопределении инициализации
- (id)init
{
[super init];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(inventoryRequested:)
name:NotificationInventoryRequested
object:nil];
return self;
}
При этом запускается метод inventoryRequested (из Inventory.m)
-(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];
}
}
При этом запускается мой метод NSTask, который я несколько раз рефакторинг по примерам
Установка BOOL для помощи при повторных запускахздравомыслие обрабатывается с помощью инвентаря. Запрашивается с использованием инвентаря ivarIsRunning
-(void)runInventoryTask
{
inventoryIsRunning = YES;
....
Я дважды проверяю свою задачу и настраиваюdInBackgroundAndNotify, добавив себя в качестве наблюдателя.
....
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;
}
Кажется, все работает нормально.Но этот метод никогда не вызывается (т.е. я не вижу обновления окна или NSLog в консоли):
-(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];
}
Кажется, что все работает нормально.Но этот метод никогда не вызывается (т.е. я не вижу обновления окна или NSLog в консоли).Я увидел этот поток и подумал, может быть, это был мой NSPanel, блокирующий цикл выполнения, поэтому я установил его как немодальный.Я также помню, как читал о том, что NSNotification не является синхронным, поэтому я подумал, возможно, потому что метод, который я вызываю с помощью NSNotification, чтобы проверить, я просто сделал это очень быстро:
- (IBAction)updateInventoryButtonPressed:(id)sender
{
inventory = [[Inventory alloc] init];
/*[[NSNotificationCenter defaultCenter]
postNotificationName:NotificationInventoryRequested
object:self];*/
[inventory inventoryRequested:self];
[self showPanel:sender];
Очевидно, что self там недопустимо,но это показало мне, что даже прямой вызов этого метода, похоже, не помог (таким образом, заставляя меня думать, что речь идет не о «блокировке» NSNotification).
Любые мысли о том, что мне не хватает, я проверил наremoveObserver где-нибудь в моем коде (я знаю, что мне нужно добавить его в dealloc и, вероятно, в readPipe: когда команда будет выполнена).Если это поможет, вот маленькая оболочка NSTextview, которая нуждается в работе, поскольку я не делаю строку \ n в строках прямо сейчас.
Inventory.h
//NSTextview
IBOutlet NSTextView * inventoryTextView;
Inventory.m
-(void)addLogText:(NSString *)text
{
NSRange myRange = NSMakeRange([[inventoryTextView textStorage] length], 0);
[[inventoryTextView textStorage] replaceCharactersInRange:myRange withString:text];
}
Любая помощь с этим также будет признана моим следующим камнем преткновения.
ОБНОВЛЕНО: похоже, вызывается этот метод readData, однако он не обновляет мой Textview до завершения NSTask,поэтому у меня проблема с управлением потоком.