2009-05-10 16 views
8

Acabo de comenzar el desarrollo en Macs y he descubierto que Cocoa es un marco útil y atenta, pero su funcionalidad HTTP me ha dejado perplejo.POST de archivo HTTP asincrónico y atómico con comentarios razonables

Tengo un objeto NSURLConnection para descargar un archivo de mi servidor web utilizando el método HTTP GET. La conexión asíncrona de NSURLConnect es excelente, obtengo muchos comentarios, obtengo cada fragmento recibido como un nuevo objeto NSData que puedo usar para reconstruir atómicamente el archivo en el extremo del cliente y, lo que es más importante, proporcionar al usuario un informe de progreso: [longitud de mis datos ]

Las cargas, sin embargo, no están ni por asomo. Puede pegar una solicitud síncrona en su propio hilo o llamar a una solicitud asíncrona (que creo que genera su propio hilo), pero ninguno le proporciona ningún comentario útil. No hay delegados que soliciten datos o incluso me avisen cuando se envíen los datos. Es de suponer que esto me limita a archivos más pequeños que la memoria disponible.

Mi pregunta es, por lo tanto, ¿hay una solución simple y elegante para HTTP POST cargar archivos utilizando Cocoa que proporciona una buena cantidad de comentarios y la capacidad de leer archivos parte por parte, en lugar de todos a la vez? ¿O debería escribir mi propia clase desde la funcionalidad de redes de bajo nivel?

Gracias!

+0

¿Por qué no dejarlos ir en sus propios hilos? Puede usar NSOperation para asegurarse de que no está creando/gestionando/etc. toneladas de hilos que no necesitas ¿Qué tipo de retroalimentación de datos espera de una operación POST? –

+0

La cantidad de datos que he cargado hasta el momento. Estoy tratando con archivos potencialmente grandes, por lo que debo proporcionar al usuario una barra de progreso o algo así. Enhebrar no es tanto el problema, es más la capacidad de cargar archivos, parte por parte y obtener comentarios. ¡Apoyos para la respuesta absurdamente rápida! – Dani

+0

¡Ah, está bien! Probablemente yo solo rodaría algo yo mismo. Estoy bastante seguro de que vi una clase decente para NSURL con funcionalidad POST una vez, pero no recuerdo dónde ... tal vez alguien agregará una respuesta decente, pero es posible que desee googlearlo un poco. Recuerdo que me llevó un poco cavar para encontrarlo yo mismo. –

Respuesta

2

Decidí ir con las funciones de CFNetwork en lugar de NSURLConnection. Parece que hay un poco más de flexibilidad en las notificaciones asincrónicas y en las características específicas (autenticación, por ejemplo). Por desgracia, es un poco más complicado (bucles por ejemplo soplar mi mente ejecución) por lo que recomiendo que lea la guía de referencia CFNetwork si usted va esta ruta:

http://developer.apple.com/documentation/Networking/Conceptual/CFNetwork/Introduction/Introduction.html

He aquí un fragmento de código desde mi rutina POST, Fwiw :

// Create our URL 
CFStringRef url = CFSTR("Submit"); 
CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, url, baseUrl); 

// Create the message request (POST) 
CFStringRef requestMethod = CFSTR("POST"); 
CFHTTPMessageRef myRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, myURL, kCFHTTPVersion1_1); 

// Connect the read socket to the HTTP request stream 
CFReadStreamRef myReadStream = CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, myRequest, readStream); 
// TODO: why does this have to be done? 
succ &= CFReadStreamSetClient(myReadStream, 
    kCFStreamEventOpenCompleted | kCFStreamEventCanAcceptBytes | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, 
    (CFReadStreamClientCallBack) &MyReadCallBack, &myClientContext); 
CFReadStreamScheduleWithRunLoop(myReadStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 
succ &= CFReadStreamOpen(myReadStream); 

1

Por desgracia, tienes toda la razón en que NSURLConnection es débil aquí. El enfoque más flexible que recomendaría es CocoaAsyncSocket. Significa rodar su propio HTTP, lo cual es desafortunado, pero en la mayoría de los casos no es tan difícil. CocoaHTTPServer muestra cómo crear un servidor HTTP completo sobre CocoaAsyncSocket, y puede tener un código útil para su problema. He encontrado que ambos son muy útiles.

Otro enfoque que puede valer la pena investigar es WebKit. Cree un WebView invisible y loadRequest: un POST. No he profundizado si el sistema estimado de notificación de cambio incluye el tiempo para cargar o solo el tiempo para descargar, pero vale la pena intentarlo.

1

Puede echar un vistazo a la sección HTTPMessage de my toolkit repository on github para obtener un envoltorio ObjC simple alrededor de CFHTTPMessageRef; entre otras cosas, te entregará un objeto NSInputStream, lo que te ahorra pensar en las funciones de devolución de llamada de C simple.

Dependiendo de lo que esté leyendo, es posible que desee echar un vistazo a la sección StreamingXMLParser del mismo repositorio para un analizador XML (y HTML) que analizará los datos directamente desde dicho NSInputStream en su nombre.

5

Es posible que desee mirar el marco ASIHTTPRequest. No lo he usado para cargar, pero parece que tiene más comentarios y el uso es bastante sencillo.

2

ASIHTTPRequest fue diseñado originalmente para este propósito (seguimiento de progreso POST), ya que en la API 2.x, esto no es posible con NSURLConnection.Definitivamente será más fácil de integrar que hacer la tuya con CFNetwork, y obtienes muchas otras cosas gratis (por ejemplo, seguimiento de progreso en múltiples solicitudes, reanudación de descargas, etc.). :)

Si los archivos que está cargando son grandes, asegúrese de mirar las opciones de transmisión directa desde el disco, para que no tenga que guardar los datos en la memoria.