2010-03-09 6 views
5

Hola: Quiero redirigir stdout a un NSTextView. ¿Podría esto también funcionar con salidas de subprocesos? ¿Cuál podría ser la mejor manera de lograr esto?¿Cuál es la mejor manera de redirigir stdout a NSTextView en Cocoa?

EDIT: De acuerdo con Peter Hosey respondo que implementé lo siguiente. Pero no recibo una notificación. ¿Qué estoy haciendo mal?

NSPipe *pipe = [NSPipe pipe]; 
NSFileHandle *pipeHandle = [pipe fileHandleForWriting]; 
dup2(STDOUT_FILENO, [pipeHandle fileDescriptor]); 
NSFileHandle *fileHandle = [[NSFileHandle alloc] initWithFileDescriptor:pipeHandle]; 
[fileHandle acceptConnectionInBackgroundAndNotify]; 

NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter]; 
[dnc addObserver:self selector:@selector(handleNotification:) name:NSFileHandleConnectionAcceptedNotification object:fileHandle]; 
+0

¿qué tiene que ver python con esto? – Eimantas

+0

@Eimantas: Tiene razón, no está directamente relacionado con la pregunta. En realidad estoy usando PyObj para comunicarme con la escritura de código de Python en ** stdout ** que quiero mostrar. Debería eliminar la etiqueta ... – Sney

Respuesta

12

Estaba buscando hacer lo mismo y encontré esta publicación. Pude resolverlo después de leer esto y la documentación de Apple. Estoy incluyendo mi solución aquí. "pipe" y "pipeReadHandle" se declaran en la interfaz. En el método init he incluido el siguiente código:

pipe = [NSPipe pipe] ; 
pipeReadHandle = [pipe fileHandleForReading] ; 
dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stdout)) ; 

[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNotification:) name: NSFileHandleReadCompletionNotification object: pipeReadHandle] ; 
[pipeReadHandle readInBackgroundAndNotify] ; 

El handleNotification: método es

[pipeReadHandle readInBackgroundAndNotify] ; 
NSString *str = [[NSString alloc] initWithData: [[notification userInfo] objectForKey: NSFileHandleNotificationDataItem] encoding: NSASCIIStringEncoding] ; 
// Do whatever you want with str 
+0

Esto me ayudó mucho. ¡Gracias! Usé su sugerencia y agregué estos dos mensajes para hacer que textView creciera y autoscroll usando lo siguiente: [myTextView setText: [myTextView.text stringByAppendingString: str]]; [myTextView scrollRangeToVisible: NSMakeRange ([myTextView.text length], 0)]; – ThinkBonobo

5

que desea redirigir la salida estándar a un NSTextView.

¿Su propia stdout?

¿Podría esto también funcionar con salidas de subprocesos?

Sure.

¿Cuál podría ser la mejor manera de lograrlo?

Los descriptores de archivos son sus amigos aquí.

Crear una tubería (utilizando NSPipe o pipe(2)) y dup2 escribir en STDOUT_FILENO. Al invocar subprocesos, no configure su stdout; ellos heredarán su stdout, que es su pipa. (Aunque es posible que desee cerrar el extremo de lectura en el subproceso. No estoy seguro de si será necesario; pruébelo y descúbrelo. Si llega a serlo, deberá usar fork y exec, y cierre el final de lectura entre.)

Lea desde el extremo de lectura de la tubería en el fondo de forma asíncrona, utilizando kevent o NSFileHandle. Cuando ingresan nuevos datos, intégrelos usando alguna codificación y añádalos a los contenidos de la vista de texto.

Si la vista de texto está en una vista de desplazamiento, debe verificar la posición de desplazamiento antes de anexarla. Si fue al final, es probable que desee volver al final después de agregar.

+0

¿He editado la pregunta con una implementación que no funciona? ¿Cualquier pista? – Sney

+0

Snej: Tienes los argumentos para 'dup2' al revés. Luego pasa un puntero NSFileHandle como descriptor de archivo para crear un NSFileHandle. Luego, pretende que el extremo de escritura es un socket e intenta aceptar una conexión, aunque nunca se devolvió ningún FD de listen (2) (porque son un conducto, no un socket). Solucione la llamada 'dup2', no pretenda que el puntero del identificador de archivo es un descriptor de archivo, no intente crear otro identificador de archivo para ninguno de los extremos, e intente * leer * desde * el final de lectura *. –

0

Para iOS use stderr en lugar de stdout.

NSPipe *pipe = [NSPipe pipe]; 
pipeHandle = [pipe fileHandleForReading]; 
dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stderr)); 

[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNotification:) name: NSFileHandleReadCompletionNotification object: pipeHandle] ; 
[pipeHandle readInBackgroundAndNotify] ; 

-(void)handleNotification:(NSNotification *)notification{ 

    [pipeHandle readInBackgroundAndNotify] ; 
    NSString *str = [[NSString alloc] initWithData: [[notification userInfo] objectForKey: NSFileHandleNotificationDataItem] encoding: NSASCIIStringEncoding] ; 

} 
Cuestiones relacionadas