Streaming between two NSURLConnections, blocking NSInputStream read blocks all connections? - iphone

I'm trying to stream data between two iOS NSURLConenctions (one downloading, the other uploading), but can't seem to make it work.
I have two NSURLConnections running simultaneously.
One is downloading content from a url using a GET request.
The other is uploading the same content just received, to another url, in the request body of a PUT request.
In the upload connection I'm using setHTTPBodyStream to specify a custom NSInputStream whose read method returns data previously received from the other connection.
Both NSURLConnections are scheduled in the run loops of separate background threads, so that any (possibly blocking) delegate callbacks don't mess with each other (and neither with the main thread).
So I thought it would work like this:
The upload connection calls [read:maxLength] (which I have overridden) on the input stream.
Since there's no data available yet, the read call blocks.
On another thread, [connection:didReceiveData:] is called on the delegate of the download connection.
It puts the received data in a shared buffer, thus making it available for the input stream of the upload connection.
The upload stream's read call now isn't blocked anymore, it can return a chunk of data.
Unfortunately in practice, this does not work. After the upload stream's read method blocks, the download connection's delegate methods (eg. didReceiveData) don't get called anymore. (Note that if I disable the blocking on the upload side, then didReceiveData on the download side does get called all right.)
I suspect that this has to do something with the fact that the upload input stream's read method is called not on the thread where the connection and the stream objects were created, but on some other thread (apparently created by Cocoa). As if this was some shared thread used by both NSURLConnections, so once it's blocked, all other connections stop working as well. Or something like that.
Does anyone have an idea about what's really happening?
Also, is there a way to control on which thread the request body input stream's read method gets called?

Related

iOS. Best way to pull data from a server (dynamic intervals) for HTTP chat client?

I am working on a chat client. To get new messages (or post new one) I have to perform GET (or POST) request. All new messages are stored via core data. At the moment I don't know how to implement it in most optimal way.
My thoughts:
On view controller init stage create background thread which will periodically checks for new messages (if conversation is active - with short period, if not - with period about 60 secs). If there are new messages, we store them in DB and signal delegate that there are new messages to display.
Friend suggested to use performSelector afterDelay, but I don't understand how to use it in my app.
Something else?
Thanks in advance.
Don't use performSelector afterDelay. Using NSTimer is much better (as the trigger for starting the next download). Also, use NSOperationQueue to manage your background tasks. Create yourself a custom NSOperation that you can instantiate and it will complete your request process. When you create a new operation to check for new messages, check if one is already in progress (there is no point having multiple requests in progress at the same time).
Other notes:
Make sure you consider the threading with regards to the Core Data store (having the operation call back to the main thread with the results will probably be easiest as the result data will always be relatively small).
If you have lots of messages being sent and you want to show constant status (like Skype does, showing you when someone is typing) you would need to use sockets to keep the connection alive the whole time (the cost of new connections each time would be prohibitive).

How to wait for a certain status of a NSURLConnection

Sorry to bother with yet another NSURLConnection question, adding to the over one thousand already here.
The scenario is as follows. In an iPhone app using dynamically loaded augmented reality features, the user is prompted to download new AR models as these are made available. The models can be several MB large, so the user should be given an indication of the total size of all models to be downloaded before deciding to do so.
To find out how large each file is I want to use an asynchronous NSURLConnection but then to stop the download once I have got the response ([NSURLResponse expectedContentLength]). I can do this in the delegate's connection:didReceiveResponse: method.
My question is, how can I wait until this condition arises? How can I setup the NSURLConnection, let it start asynchronously and then wait until the connection:didReceiveResponse: method is called? I have tried using a NSCondition, letting this wait after setting up the NSURLConnection and in the connection:didReceiveResponse: method signalling the condition. But all this did was to freeze the main thread. Any ideas?
Maybe you could send a HEAD request instead of GET. This may depend on your server set up, but that should get you just the headers, including Content-Length. You ought to be able to use a NSMutableURLRequest so you can change the request method, and then read expectedContentLength on the response as usual.

HTTP Request process line by line

I have an iOS app that I'm migrating from the very slow and clunky SOAP to a custom data format (basically CSV with some extra bits).
My priority is getting initial data to the client as quickly as possible while letting it still load more in the background. The server side is written to continuously flush data instead of caching the response.
So I'd like to parse out every line as they arrive at the client, instead of waiting for the full response.
If I view it in a browser I get progressive loading. However, using MKNetworkKit or ASIHTTPRequest or similar, I'm only able to get the full response which takes several seconds longer.
Does anyone know what the best options could be?
NSURLconnection can do what you want. You set the delegate and use -connection:didWriteData:totalBytesWritten:expectedTotalBytes: callback to read in a chunk of the data as it's downloading.
It will be up to you to properly handle splitting up the lines and handling chunks containing partial lines.

Design choice with AVQueuePlayer and hpple

I'm designing an iPhone app that plays 3 files in sequence, using the AVQueuePlayer class.
The 3 urls that I need to play in sequence must be extracted first from an .htm file, using the http:// protocol. For that purpose I'm using the TFHpple class, from here hpple git project
My problem is that my AVQueuePlayer player must run on the Main Thread, and when I try to parse the .htm file the screen doesn't respond to any touch.
I need the urls first, that are contained on these .htm files to be parsed, and then feed the urls to the AVQueuePlayer player.
I was reading the Apple documentation that says that multi threading is a poor choice for Networking applications, but I need to use hpple to parse the .htm content.
How to solve this problem?
If using AVQueuePlayer on the main-thread but triggered from a different thread is the only issue, simply wrap its startup using a method that is invoked from the other thread using performSelectorOnMainThread.
From the NSObject reference;
- (void)performSelectorOnMainThread:(SEL)aSelector
withObject:(id)arg
waitUntilDone:(BOOL)wait
Invokes a method of the receiver on the main thread using the default mode.
Discussion
You can use this method to deliver messages to the main thread of your application. The main thread encompasses the application’s main run loop, and is where the NSApplication object receives events. The message in this case is a method of the current object that you want to execute on the thread.
This method queues the message on the run loop of the main thread using the common run loop modes—that is, the modes associated with the NSRunLoopCommonModes constant. As part of its normal run loop processing, the main thread dequeues the message (assuming it is running in one of the common run loop modes) and invokes the desired method. Multiple calls to this method from the same thread cause the corresponding selectors to be queued and performed in the same same order in which the calls were made.
You cannot cancel messages queued using this method. If you want the option of canceling a message on the current thread, you must use either the performSelector:withObject:afterDelay: or performSelector:withObject:afterDelay:inModes: method.
Additionally, I would recommend looking into RaptureXML for parsing xHTML as it is lean, fast and convenient.

NSMutableURLRequest with large files

I'm writing an iPhone app that requests data from a web service, and in order to get that data, I'm using NSMutableURLRequest.
The problem that I am having is that the amount of data being requested is quite large (~11Mb), and this is causing my app to be killed by the OS.
Is there any way of streaming the data in a way that will allow me to process chunks of it, or should I just split the request over several separate requests in order to prevent the memory load spiking?
Think about converting your use of NSMutableURLRequest to an NSURLConnection. That class provides a way to specify a delegate object that will receive a series of connection:didReceiveData: messages, each of which will have some chunk of data from your web server. You can implement this method in your delegate in such a way that it will process data as it becomes available while still waiting for more data from the connection.