Атомный, асинхронный HTTP-файл POST с разумной обратной связью? - PullRequest
8 голосов
/ 11 мая 2009

Я только начал разработку для Mac и обнаружил, что Cocoa - полезный и продуманный фреймворк, но его функциональность HTTP меня озадачила.

У меня есть объект NSURLConnection для загрузки файла с моего веб-сервера с использованием метода HTTP GET. Асинхронное соединение NSURLConnect отличное, я получаю много отзывов, каждый чанк получаю в виде нового объекта NSData, который я могу использовать для атомарной перестройки файла на стороне клиента и, что важно, предоставить пользователю отчет о ходе выполнения: ].

Загрузки, однако, далеко не такие аккуратные. Вы можете либо вставить синхронный запрос в свой собственный поток, либо вызвать асинхронный запрос (который, я считаю, порождает свой собственный поток), но ни один из них не предоставит вам полезной обратной связи. Там нет делегатов, чтобы запросить данные или даже сообщить мне, когда данные отправляются. Предположительно, это ограничивает меня файлами меньше доступной памяти.

Поэтому мой вопрос заключается в том, существует ли простое и элегантное решение для загрузки файлов HTTP POST с использованием Какао, которое обеспечивает хорошую обратную связь и возможность читать файлы по частям, а не все сразу? Или я должен написать свой собственный класс из низкоуровневой сетевой функциональности?

Спасибо!

Ответы [ 5 ]

5 голосов
/ 12 мая 2009

Возможно, вы захотите взглянуть на ASIHTTPRequest инфраструктуру. Я не использовал его для загрузки, но похоже, что у него больше отзывов, и использование довольно простое.

2 голосов
/ 13 мая 2009

ASIHTTPRequest изначально был разработан специально для этой цели (отслеживание прогресса POST), поскольку в API 2.x это невозможно с NSURLConnection. Это, безусловно, будет проще интегрировать, чем сворачивать свою собственную с CFNetwork, и вы получите множество других бесплатных ресурсов (например, отслеживание прогресса по нескольким запросам, возобновление загрузок и т. Д.). :)

Если файлы, которые вы загружаете, имеют большой размер, обязательно посмотрите параметры потоковой передачи непосредственно с диска, чтобы вам не приходилось хранить данные в памяти.

2 голосов
/ 11 мая 2009

Я решил использовать функции CFNetwork вместо NSURLConnection. Кажется, что есть немного больше гибкости в асинхронных уведомлениях и в определенных функциях (например, аутентификация). К сожалению, это немного сложнее (например, циклы выполнения поражают воображение), поэтому я рекомендую вам прочитать справочное руководство CFNetwork, если вы пойдете по этому пути:

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

Вот фрагмент кода из моей процедуры POST, FWIW:

</p> <pre><code>// 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 голос
/ 11 мая 2009

Вы можете взглянуть на раздел HTTPMessage моего репозитория инструментария на github для простой обертки ObjC вокруг CFHTTPMessageRef; помимо всего прочего он передаст вам объект NSInputStream, который избавит вас от размышлений о функциях обратного вызова plain-C.

В зависимости от того, что вы читаете, вы можете взглянуть на раздел StreamingXMLParser того же хранилища для синтаксического анализатора XML (и HTML), который будет анализировать данные непосредственно из указанного NSInputStream от вашего имени.

1 голос
/ 11 мая 2009

К сожалению, вы совершенно правы, что NSURLConnection здесь слабый. Наиболее гибкий подход, который я бы порекомендовал, это CocoaAsyncSocket . Это означает использование собственного HTTP, что, к сожалению, не так сложно. CocoaHTTPServer демонстрирует, как создать полноценный HTTP-сервер поверх CocoaAsyncSocket, и может содержать много полезного кода для вашей проблемы. Я нашел оба эти очень полезными.

Еще один подход, который стоит изучить, - это WebKit. Создайте невидимый WebView и loadRequest: POST. Я не выяснил, включает ли система уведомлений о предполагаемом изменении время загрузки или только время загрузки, но стоит попробовать.

...