iPhone upload image speed advice - iphone

I have an app that allows you to take a picture, adjust the jpeg quality size (10-100%) and then send it to a server using ASIFormDataRequest (part of the ASIHTTPRequest implementation). This works fine over a network connection, but over the celluar network it appears to sit there for 5-10 minutes attempting to transmit the image post data, before failing (even with the quality at 10%).
On comparing this to the image uploads that the Twitter and Facebook apps provide (which take ~30 seconds to a minute) this isn't exactly ideal. I wondered if anyone could give me any advice about either how to speed up my data transfer, or monitor it so I can see exactly where the problem lies.
Once I get back to my mac laptop tonight I'll post a code snippet of exactly what it is I'm doing, in case that helps.
EDIT: Heres the code snippet:
NSURL *url = [NSURL URLWithString:#"...upload.php"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
NSTimeInterval time = [[NSDate date] timeIntervalSince1970];
NSString *fileName = [NSString stringWithFormat:#"%d", time];
...
float compressionRate = [userAccountView getCompressionRate];
NSLog(#"Compression rate: %.1f", compressionRate);
NSData *imageData = UIImageJPEGRepresentation(imageForView, compressionRate);
[request setData:imageData withFileName:fileName andContentType:#"image/jpeg" forKey:#"userfile"];
[request setDelegate:self];
[request startAsynchronous];
The .. code comment is where I just stick an 'uploading' image over the view. I suppose I could make the call synchronous as opposed to asynchronous, do you think that may improve performance? I have left it that way in case at a later stage I wanted to allow the user to do other bits while it is uploading.
Any advice would be great :)
Thanks,
Dan
EDIT:
Jesse, thanks for the comment - I added in [request setUploadProcessDelegate:self] and put in the required method to monitor the data that was being sent, and it all seemed to be sending okay.
JosephH - I have added in "[ASIHTTPRequest setShouldThrottleBandwidthForWWAN:YES]" as suggested, and have also added "set_time_limit(0);" into the PHP upload script (in case of timeouts) and now the data does seem to be sending and being retrieved over the cellular network, so horray! Am playing around now with file compressions etc. to find the best one for the best quality. ATM it seems like 0.3 is pretty good quality, and transfers in roughly 30 seconds or so, which is what I was looking for!
I was also incorrectly setting the compression rate, as I was using 10-100 as opposed to 0.0-1.0, so I have also corrected that.
Thanks for your quick help guys in solving my issue!!

I think the first thing to do is to check what size the data you're sending is:
NSLog(#"imageData size = %d", [imageData length]);
Does your NSLog correctly show the compressionRate is set to 0.1 for 10%?
ASIHTTPRequest also has a lot of debug logging you can enable - see ASIHTTPRequestConfig.h; just change everything from 0 to 1. It may not reveal anything of interest, but it is certainly worth looking at.
Are you calling [ASIHTTPRequest setShouldThrottleBandwidthForWWAN:YES] ?
When it fails, how does it fail, what is the error, what does any logging on the server show?
(If you find out anything extra, please do edit it into the question and post a comment and I'll take another look)

Related

Unable to upload video longer than 6 - 7 mins to server in iOS

I am trying to upload large files from my app to web server using a web service.
I am reading the video into an NSData instance and converting that into a base64 encoded string. I then pass the string to webservice. I even tried degrading the quality of video to low while uploading still I am not able to upload video above 5 min on server, the server just stops responding.
When I check the encoded data from server it is not receiving it completely. I think the size of the file is so large that it's not getting sent properly. Below is some of my code. I tried many options mentioned in many posts but still am not able to upload videos properly as per my client's requirement. I have successfully uploaded videos up to 4 to 5 mins long with low quality but not able to upload big videos. Please help me out.
NSData *videoData = [NSData dataWithContentsOfURL:urlVideo];
pictureDataString = [videoData base64Encoding];
----other code
xml = [xml stringByAppendingString:[NSString stringWithFormat:#"<BinaryData>%#</BinaryData>",pictureDataString]];
...other code
After generating my entire xml I am using the following code:
url = [NSURL URLWithString:#UploadMemory];
serviceRequest = [ASIHTTPRequest requestWithURL:url];
[serviceRequest setShouldStreamPostDataFromDisk:YES];
[serviceRequest addRequestHeader:#"Content-Type" value:#"text/xml"];
[serviceRequest appendPostData:[xml dataUsingEncoding:NSUTF8StringEncoding]];
[serviceRequest setTimeOutSeconds:86400];
[serviceRequest setDelegate:self];
[serviceRequest startAsynchronous];
I even tried to split the NSData instance into multiple parts and send separate XML files to the server so I can save my time and be able to upload large video files to the server, but I'm still not able to do so successfully.
It take ages while the encoding the data to base64 so I am not able to split the encoded string in order to send multiple xml to server. Please, suggest a better way to do this.
I have one more option in mind for this if some one can tell me how to read data files in binary format in iOS so I can read video file in binary split that make NSData and then convert it to base64encoding so that may work.
Many thanks ....
Any chance you are doing the encoding on the main thread? If so, the watchdog timer on iOS after a given amount of time could have decided your app has crashed and booted your process out. If that's the case you'll need to do your encoding on a background process.

NSURLConnection Hanging

I have an iOS 5 app that uses NSURLConnection to load some XML via GET. On very rare occasions connections appear to get stuck in a condition where they timeout repeatedly.
An example request:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:url]];
/*
The request is set with a timeout interval of 10 because (due to the nature of
the app and the XML feed) this data is reloaded every 15 seconds.
*/
[request setTimeoutInterval:10];
[request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
[request setHTTPMethod:#"GET"];
self.afOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
self.afOperation.successCallbackQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);
self.afOperation.failureCallbackQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);
//snip success/completion block code
[self.afOperation start];
So far I've seen three "recovery" scenarios when the requests begin to hang.
Quit the entire app
Plug the device into a computer (yes, really). Right after the iPhone/iPad acknowledges the connection it will immediately stop timing out.
Leave the app and go do something else for awhile. Quickly leaving and reentering the app is typically insufficient to cause recovery.
As you might imagine, I find this incredibly bizarre. At this time I've replaced my own NSURLConnectionDelegate implementation with AFNetworking (as seen above) and am still running into the same problem. I've added logging to every NSURLConnectionDelegate protocol selector and found that the only selector called (after calling start) is connection:didFailWithError:. I've ensured I'm not piling up multiple requests (the previous request is always canceled and nil'd before starting a new one). Additionally, I've verified that no request is actually being sent via tcpdump on my router. What could cause this type of behavior?
It turns out this problem is caused by the TestFlight SDK v1.0 and below. See Why does NSURLConnection fail to reach the backend?
Until they release a fix there's no way to workaround the problem short of stripping out the SDK entirely.
I started seeing the error after installing the testflight sdk, and removing it helped me get rid of it. However, I think it's caused by the interaction between Testflight and ASIHttpRequest (or whichever rest kit you use). It can also be possibly resolved by the following the solution in the link below (disabling compiler optimization on your ASIHttpRequest and ASIFormDataRequest files in your build phases)
https://groups.google.com/forum/?fromgroups#!topic/asihttprequest/fw7PDcD2wKI%5B1-25%5D

Can you track download progress on ASIFormDataRequest?

I am having a problem tracking the download progress for ASIFormDataRequest.
I can easily get the upload progress but not the download.
In the example on the ASIHTTPRequest site they use ASIHTTPRequest to show download progress.
So is it possible to get the download progress for the ASIFormDataRequest?
I already checked if I get the Content-Length response from the server, dunno what else I am doing wrong.
My setup.
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
request.downloadProgressDelegate = progressIndicator;
[request setShouldAttemptPersistentConnection:NO];
[self performSelectorOnMainThread:#selector(showProgress:) withObject:[NSNumber numberWithInt:0] waitUntilDone:NO];
[request startSynchronous];
The problem with the download progress for ASIFormDataRequest was that I didn't take into consideration the time server is processing the request.
When the ASIFormDataRequest reaches the server it waits until the server responds with the data. If you have to wait for server to perform some kind of calculation this period may take some time.
In my case the upload was super fast as well as the download, hence I could not see the progress, it was always 0 to 100%. The only process that was long and that got me confused was the calculation process the server was performing which in my case is undeterministic.
In short, all was working well, except my understanding... It happens all the time :-)

Is it possible to read the contents of a web page into a string so i can parse out the data?

I'd like to be able to get my iphone to load a URL( or really the file that the url points to) into a string. The reason I want to be able to do this is so that I can then parse the string looking for tags and extract some values from it.
The files are mostly webpages so html or .asp etc.
Anybody able to give me some hints on what I need to do to achieve this kinda of thing?
Many Thanks,
-Code
First get the URL
NSURL *anUrl = [NSURL URLWithString:#"http://google.com"];
Then turn it into a string
NSError *error;
NSString *htmlString = [NSString stringWithContentsOfURL:anUrl encoding:NSUTF8Encoding error:&error];
UPDATE:
There is documentation on getting the contents of an URL by using NSURLConnection from the ADC site
From there you can get the string representation of the downloaded data using
NSString *htmlString = [[NSString alloc] initWithData:urlData encoding:NSUTF8Encoding];
I appreciate that this has been asked and answered, but I would strongly suggest that you consider not using NSString's stringWithContentsOfURL:encoding:error: method for this. If there's one message Apple has tried to send to iOS developers over the past year it is this: Do not make synchronous network calls on the main thread.
If that request takes more than twenty seconds to respond, which is not at all unlikely with a 3G or EDGE connection, and certainly possible on a WiFi connection, iOS will kill your app. More importantly, if it takes more than about half a second to return you're going to anger your users as they fiddle with their unresponsive phones.
NSURLConnection is not terribly difficult to use, and will allow your device to continue responding to events while it's downloading content.

How to read / write data to a web server in an iPhone app

I am working on an iphone application which would be able to retrieve/publish information from/to a web server. I want to use out-of-the-box technology on the server side and as much built-in iphone capabilities as possible. Here are my thoughts so far:
I initially thought about using rss feeds:
Writing an rss reader is quite straightforward.
However I do not seem able to find information regarding the publishing of an rss article from the iphone. Does anyone have a smart idea on this point?
I then thought of setting up dedicated email accounts (once again it's a prototype app).
Sending then becomes easy via the iphone. Receiving emails from within a custom iphone ap however seems pretty involved. Once again: any smart thought on this?
There are probably other ways of doing what I want which elude me. Any constructive suggestions would be very much appreciated.
I would guess it depends on how much data you want to push back to your server. If its just a few items I would sent a request to a php page on your server and have it update a database with the info. You can use GET or POST. Not sure what the limits are but we do this with our app to get data on what movie the user has requested, the UUID and other useful data.
For example:
NSString * uId = [[UIDevice currentDevice] uniqueIdentifier];
NSString * episodeString = [URLString substringFromIndex:73]; //strip out the stuff before the enclosing folder
NSArray * episodeArray = [episodeString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"/"]];
NSString * resVersion = episodeArray.lastObject; // get either small.mov, medium.mov or large.mov
NSString * episode = [episodeArray objectAtIndex:0];// get the enclosing folder
NSMutableURLRequest *statsRequest = [[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:kAppStats]] autorelease];
[statsRequest setHTTPMethod:#"POST"];
NSString *requestBody = [NSString
stringWithFormat:#"episode=%#&res=%#&uuid=%#",
[episode stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[resVersion stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[uId stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
];
[statsRequest setHTTPBody:[requestBody dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *statsConnection = [[NSURLConnection alloc] initWithRequest:statsRequest delegate:self];
[statsConnection start];
[statsConnection release];
This is sent to a php script that gets the data through standard POST and updates a MySQL database. Don't see why you couldn't do something similar.
It is difficult to tell precisely whether the built-in capabilities of the iOS API will do exactly what you want, however what you have described sounds like it could be accomplished quite readily by creating a Safari (browser) application, rather than worrying about custom iPhone development.
RSS feeds are typically managed on the server and consumed by the client. I can't tell from your description how the emails are involved, but again if you are processing your feeds and emails on the server, a browser based application will have everything it needs.