Currently I am working on an App which requires several calls to a back-end server.
When on WiFi the App connects fine and downloads very fast the data, but when on 3G the connection seems a bit unstable and very slow.
So I have done some very simple test case (which you find below). And it seems that NSURLConnection is not getting data at the same response speed.
(Do note that I have removed the URL of the real server I connected to)
Test cases:
Placed on a server the following php script:
<?php echo 'hello world' ?>
Grabbed an iPhone, put WiFi off and made sure it had a proper 3G connection.
Used the following Objective-C code to connect to the server:
NSURL * url = [NSURL URLWithString:#"http://someserver.com/test.php"];
NSURLRequest * request = [NSURLRequest requestWithURL:url];
NSDate * startDate = [NSDate date];
NSLog(#"START");
NSURLConnection * connection = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSLog(#"%3.2f", -[startDate timeIntervalSinceNow]);
This returns on 3G - 1.47 seconds. So this might be normal if you connect for the first time using 3G, since it needs to initialise. But now comes the interesting part. If you repeat this call several times it returns the following:
1.47 seconds
2.33 seconds
1.1 seconds
I have tested this using two different iPhones and two different providers:T-Mobile and KPN. I also tried this using the async version of NSURLConnection, which I normally use, but this also returns the same results.
(Other things I also did: checked Apple's Reachabilty.h, removed the DNS look-up by replacing the server url by the ip-number, used an other server and used https://www.google.nl/search?q=%i, arc4random(), also tried [NSString alloc]initWithContentOfURL]. All returned a similar result, except when using the iPhone browser: Safari, which responded immediately.)
I have also tested something similar using an Android phone, but then I get a fast response 500ms (using the same providers).
Did someone encountered this before? If so, how did you solve this issue and what causes this problem with the connection?
I have a similar issue in that naturally over a 3g connection the post request would be slightly slower depending on the amount of data sent. However if I send over a synchronous request its quicker for me than the async method. What I have noticed is that over a 3g connection using async the OS has to close the connections and you may notice in the log "purgeIdleCellConnections: found one to purge conn" seems to add some time to method execution.
Related
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
I have a simple HTTP server running that pretty much just serves an MP3 file in chunks of equal size. I'm writing an iOS app (for testing purposes), that basically takes a URL and streams the file through MPMovieController. Here's my sample code:
MPMoviePlayerController *mp = [[MPMoviePlayerController alloc] init];
[mp setMovieSourceType:MPMovieSourceTypeStreaming];
mp.contentURL = [NSURL URLWithString:#"http://127.0.0.1:8080"];
[mp play];
It works. BUT: on my http server I see multiple connections (first one breaks right away, second one streams to the end usually, although sometimes there is 3rd connection).
I know it's not the server issue, since when I do this:
NSData *myData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://127.0.0.1:8080"]];
...then there's only 1 connection that finishes reading and disconnects.
The question is: Why does MPMoviePlayerController need to establish and break those connections before finishing reading the file, why doesn't it just keep waiting for more data to be written on the socket? I haven't been able to find any relevant docs that would explain this :(
P.S. If you are curious why I need this, here's a short explanation: I'm trying to emulate real life network scenarios where bytes are received by the MPMovieController in chunks with small delays of random length in between
You need to modify your server and add support for HTTP 206 Partial Content requests/responses. iOS requests movie data over HTTP this way.
I'm using SBJson to retrive data from URL. How to check if I have access to the URL before downloading. I want to check this, sometime application crash if there is no network connection.
Here is my code
id response = [self objectWithUrl:[NSURL URLWithString:#"http://myurl.com/Service.svc/GetId"]];
*I'm using stringWithUrl and objectWithUrl method to download the JSON.
Use the Reachability API and use that URL as your hostname you are testing
http://developer.apple.com/library/ios/#samplecode/Reachability/Introduction/Intro.html
//reachabilityWithHostName- Use to check the reachability of a particular host name.
+ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
Do NOT use Reachability on the main thread to detect whether you have a network connection. It doesn't work and can lock up for 30 seconds or more, causing your app to be terminated.
Instead you should simply try downloading the data using an NSURLConnection -- this will power up the radio(s) if needed. You will get a callback if an error occurs.
All network connections -including domain name lookups- should be on secondary threads or asynchronous or at least nonblocking. In the case of NSURLs, use NSURLConnection's asynchronous callbacks.
Your application is probably crashing because you are are making a network call from the main thread and locking up for more than 30 seconds, so the system watchdog timer kills you. Looking at your crash logs in Xcode should verify that. Otherwise, you probably just aren't handling the error condition properly.
So I have a pretty simple problem, which I have no idea how to go about (kinda of new for everything here). I am developing an iPhone app that I intend to use only myself - so think small for now :)Let's say all my app is doing is tracking my location every hour. All I want to do, is to be able to read this information not on the iphone, say on a file on my computer. How can I send this information from my app to a personal computer? I am guessing that I will need to set up some server / database or something on my personal machine?
Can someone please help with a quick step by step on how to go about that? I literally have no clue where to start...
Thanks!
You just need a http server and then you cam create HTTP GET/POST requests to url's set up on your machine. You can use the responses to send data back to the device.
You'll need to have a listener somewhere to send your data to. For instance, you could set up a communication class in your project which would be responsible for serving as the medium between your applications. You would then set up a listener on a server, or your machine that would listen for requests.
iPhone > Communication Class > Web service
(.NET in this case)
You can use the NSURLConnection object to serve this purpose. E.g.
- (void) sendSomethingToServer:(NSString*)myData{
NSString*url = [[NSString alloc]initWithFormat: #"http://example.com/service.asmx/RecordData?myData='%#'", myData];
[self createRequest:url];
[url release];
}
http://example.com/service.asmx/RecordData being the location and method on your web service.
Here's a generic request method I created which sets the headers as a JSON packet.
- (void) createRequest: (NSString*)urlFormatted {
NSLog(#"Request Sent");
NSURL *url = [NSURL URLWithString: urlFormatted];
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL: url];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/json; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
}
And on the back-end, on your web server, you would have a method that recieves the data. Obviously you could use any technology you wanted on the server. In this example, I'm using .NET on Mono e.g.
[WebMethod(Description = "Generic Client Data)]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public string RecordData(string myData)
{
// Do something with data
}
Set up a Ruby on Rails server on your Mac. It's free and quite easy.
Use ASIHTTPRequest to send data to the Ruby server.
http://allseeing-i.com/ASIHTTPRequest/
If you just need to get the data back and forth, I believe you could use file sharing. Here's a tutorial on how to set that up:
http://www.raywenderlich.com/1948/how-integrate-itunes-file-sharing-with-your-ios-app
It would allow you to view the files in itunes and copy them back and forth when the iPhone is connected via USB. If all you need to do is to get a raw data file onto your computer, that would likely be a lot less overhead than having to build/run a full server just to transfer the file over.
Apple's can you help get started. Search for "networking" in the docs and develop a client on both sides which uses your own protocol.
when iPhone connects to a wireless router, and that router is not connected to the internet? i need to display an error message saying "check you internet connection" i tried the Reachability sample code. but no luck,
http://developer.apple.com/library/ios/#samplecode/Reachability/Listings/ReadMe_txt.html
when i disable the WIFI in phone it's working fine, i tried the Checking For Internet Connectivity in Objective C sample code "isDataSourceAvailable" even itz not working,can any one help me to fix this issue, really appriciate.
You could do something like this:
+ (BOOL) pingServer
{
NSURL *url = [NSURL URLWithString:#"http://some-url-that-has-to-work/"];
NSURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSHTTPURLResponse *response = nil;
[NSURLConnection sendSynchronousRequest:request
returningResponse:&response error:NULL];
return (response != nil);
}
This is a synchronous request, so that it will block the current thread. You can do the whole network check in a background thread, so that blocking it won’t matter, or you can send the request asynchronously. Also you might want to set the HTTP method to HEAD, so that you won’t download the whole resource.
I recommend you do the same as Microsoft does, and to be really wicked, you can even use their servers, since they probably will make sure those are on line for the foreseeable future.
They look up a hostname and then access a very small file on a web server.
See the same question on serverfault (from a non programming perspective of course.)
Basically look up the IP address for a hostname (in that example "dns.msftncsi.com"), then access the URL, for example http://msftncsi.com/ncsi.txt. This can be done with simple socket programming if you like, real HTTP not necessary.
Open a socket to port 80, on the IP you found by looking up the hostname.
Send a string to the socket like so:
"GET /msftncsi.com/ncsi.txt HTTP/1.1\nHost: msftncsi.com:80\n\n"
Then wait for something to return. If anything returns, even a single byte, it means you have Internet access.
Or at least access to this server, which in this example is Microsoft.
https://github.com/adib/asi-http-request/blob/master/External/Reachability/Reachability.h
This is a part of the ASI HTTPRequest project on git. It extends Apple's example and apparently is good enough for quite a few apps in the store (see ASI's wall of who's using: http://allseeing-i.com/ASIHTTPRequest/Who-is-using-it)
Anywho, I know an answer was already accepted, but just for further reference.