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.
Related
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.
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.
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?
I am developing an iPhone application which streams data(e.x.ECGData like points) from a server and displays(means Plotting) it on the screen -- i.e., live streaming. For that purpose, I am using NSURLConnection.
The problem I am facing is that, since the data is coming so speedily from the server to the iPhone, the cache buffer is increasing rapidly, causing the displayed data to lag behind the actual data coming from the server. After some time, the application goes too slowly, and gets a memory warning.
So my question is, how should I handle this data coming from the server? Should I continue with NSURLConnection or go for lower level socket programming?
I propose you implement some sort of flow control:
The simplest approach is to drop data if your buffers are full. For video streams, frames can be dropped. I don't know whether the same is possible with your data.
Another approach is to switch from the event-based API of NSURLConnection (where the framework controls when you have to react) to CFSocket class where you can read data when you are ready for it. It's more low-level, requires a separate thread and some advanced logic like going to sleep when the buffer is full and being woken up when the main thread has displayed more data and made more space in the buffer. With this approach you are basically building on top of TCPs flow control mechanism.
Yet another approach would be to use another network protocol where you have more control about the amount of data being sent.
I would use ASIHttpRequest streaming. You can implement a delegate method request:didReceiveData: to get your data in chunks as it comes in, deflate it if needed pares it and display. If you need cache you can always save it to file.
I am just testing an app to get data off our web server, previously I had been using:
NSURL, NSURLRequest, NSURLConnection etc. to get the data that I wanted.
But I have just noticed that if I swap to using XML I can simply do the following and pass the results to NSXMLParser:
NSURL *url = [NSURL URLWithString:#"https://www.fuzzygoat.com/turbine?nbytes=1&fmt=xml"];
Am I right in thinking that if your just after XML this is an acceptable method? It just seems strongly short compared to what I was doing before?
gary
That code only creates a URL object that represents a URL. It doesn't make any request or download any data. You still need to use NSURLRequest and NSURLConnection in order to actually download any data from the server.
Also, stay away from methods like 'initWithContentsOfURL:` and friends, unless you understand that they will block the thread that they are called on until complete. For network services, this method shouldn't be used because it'll block your UI for an indeterminate time, because you can't predict how fast the internet connection will be wherever the app is used.
NSURLConnection's asynchronous request system is exactly what you need. It won't block the UI, and provides a nice encapsulated interface to downloading data from a remote location.
This is definitely the right way to go. There do exist many different connection methods (including my favorite, ASIHTTPRequest) and many, many different xml parsers (including my favorite, KissXML) that are faster or more memory efficient than the Apple built in methods.
But to answer your question, yes, your logic and design pattern is correct.
UPDATE: Because Jasarien seems to think the question talks about asynchronous actions, I will discuss that here. ASIHTTPRequest handles async very very easily. Just check out the quick samples.
Depending on how much XML you get back from the web service, NSXMLParser may not be ideal because the entire XML document has to be read into memory.
Memory is pretty scarce on an iPhone, so using a SAX parser like that in libxml2 is probably better for larger XML files. Instead of reading the entire document into memory, the XML is streamed through and parsed for specific nodes of interest. The memory overhead is lower because less data is stored at once.
Once a node of interest is parsed, an event handler is called to do something useful, like store the node data somewhere.
In this case, take a look at Apple's XMLPerformance sample project for example code.