Today, I was testing the reachabilityWithHostName, and I'm typing a domain that is timing out inside the network that I'm joined, but the reachability its returning as its there a connection.
Why is might this be occurring?
Thanks
Here is my ping log:
PING 188.121.62.144 (188.121.62.144): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
Request timeout for icmp_seq 4
Request timeout for icmp_seq 5
Request timeout for icmp_seq 6
Here is my code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
Reachability* reachability = [Reachability reachabilityWithHostName:#"188.121.62.144"];
NetworkStatus remoteHostStatus = [reachability currentReachabilityStatus];
if(remoteHostStatus == NotReachable)
{
isInternet = NO;
}
else if (remoteHostStatus == ReachableViaWWAN)
{
isInternet = TRUE;
}
else if (remoteHostStatus == ReachableViaWiFi)
{
isInternet = TRUE;
}
if (!isInternet)
{
NSLog(#"No connection");
}
else
{
NSLog(#"There is connection");
}
return YES;
}
Can you try to ping with the below modified code .
Reachability* reachability = [Reachability reachabilityWithHostName:#"http://188.121.62.144"];
The Reachability class and -reachabilityWithHostname: is designed to be a quick, fail-fast mechanism to determine whether you have basic network connectivity to the host. If you need to verify that a particular URL can be downloaded, you need to be looking at using NSURLConnection to retrieve the contents of the URL in order to verify that it is truly available.
Depending on whether you need to do this in the foreground or background, you can either use the simple-but-blocking:
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error
or you can use the more complicated method of creating an NSURLConnection object, setting up a delegate to receive responses and wait for those responses to come in.
For the simple case:
NSURL *myURL = [NSURL urlWithString: #"http://188.121.62.144"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: myURL];
[request setHTTPMethod: #"HEAD"];
NSURLResponse *response;
NSError *error;
NSData *myData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];
If you receive back a non-nil myData, you've got some kind of connectivity. response and error will tell you what the server responded to you (in the case of response and if you received a non-nil myData) or what kind of error occurred, in the case of a nil myData.
For the non-trivial case, you can get good guidance from Apple's Using NSURLConnection.
If you don't want to stall your foreground process, you can do this two different ways. The above documentation will provide information on how to implement the delegate, etc. However, a simpler implementation would be to use GCD to send the Synchronous request on a background thread, and then message yourself on the main thread when you are done.
Something like this:
NSURL *myURL = [NSURL urlWithString: #"http://188.121.62.144"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: myURL];
[request setHTTPMethod: #"HEAD"];
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, NULL), ^{
NSURLResponse *response;
NSError *error;
NSData *myData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];
BOOL reachable;
if (myData) {
// we are probably reachable, check the response
reachable=YES;
} else {
// we are probably not reachable, check the error:
reachable=NO;
}
// now call ourselves back on the main thread
dispatch_async( dispatch_get_main_queue(), ^{
[self setReachability: reachable];
});
});
Related
I have a nested loop of sending the request.
-(void) download
{
for(NSString *id in array)
{
//init with request and start the connection
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy: NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request deletegate:self];
[conn start];
}
}
-(void) connection:(NSURLConnection *) connection didReceiveData:(NSData *) data
{
//enter here secondly
}
-(void) connectionDidFinishLoading:(NSURLConnection *) connection
{
//enter here last, after finish the for loop
//my intention is use the downloaded data to do something before sending a new request.
}
The problem is that I want to enter "-(void) connectionDidFinishLoading:(NSURLConnection *) connection" first before send the request again in the for loop.
But currently it will finish the for loop and sent all the request before enter to "-(void) connectionDidFinishLoading:(NSURLConnection *) connection".
You Should Try This NSURLConnection is deprecated in iOS9
for (NSString *URL in URLArray) {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// check error and/or handle response here
}];
[task resume];
}
and use dispatch_group_t group = dispatch_group_create();
add line to for loop dispatch_group_enter(group); will call
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// Request Finish
});
for your goal
In your case you need to try block function because as per your requirement you want response of the first connection for another request.
for(NSString* url in array)
{
// Generate a NSURLRequest object from the address of the API.
NSURL *url = [NSURL URLWithString:urlLink];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Send the request asynchronous request using block!
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
NSLog(#"Error in updateInfoFromServer: %# %#", error, [error localizedDescription]);
} else if (!response) {
NSLog(#"Could not reach server!");
} else if (!data) {
NSLog(#"Server did not return any data!");
} else {
[self doStuffWithData:data];
}
}];
}
URL loading is not a synchronous operation (or at least should never be done synchronously), because it can take up to 90 seconds just for a DNS lookup failure, and almost infinitely long if the server keeps dribbling out data. If you block the main thread for even a fraction of that amount of time, iOS will kill your app.
Instead of scheduling the requests in a loop and waiting for them to finish, you need to schedule the first request (and only the first request). Then, in your connectionDidFinishLoading: method (and maybe your connection:DidFailWithError: method), schedule the next request.
With that said, unless you still need to support iOS 6/10.8 and earlier, you should probably be using NSURLSession. (The same general advice applies; the delegate method names are changed to protect the guilty.)
I check internet connection following way.
in viewDidload
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
then
- (BOOL)connected {
return [AFNetworkReachabilityManager sharedManager].reachable;
}
But even if i don't have internet connection but 3g is on, it still returns true.
How can i detect if the real internet connection exists?
Reachability being true doesn't mean that the next network access you do will succeed -- you need to assume that network access can always fail.
It's good at letting you know the user has turned off network access (like Airplane mode), but if you are on a bad network, dropping lots of packets, then Reachability will still return true. It should also detect if you can't get any Wifi or 3G at all. But, if you have one bar -- it's going to return true, even if that means that network access won't really work.
I did it this way. I know it's no elegant, but...
+ (void)checkInternet:(connection)block
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSURL *url = [NSURL URLWithString:#"http://www.google.com/"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = #"HEAD";
request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
request.timeoutInterval = 10.0;
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
block([(NSHTTPURLResponse *)response statusCode] == 200);
}];
}
i am new in ios , i want to make one app , in app i have to call a webservices in background ,
background code is working properly but when i try to call webservices not go to on "connectionDidFinishLoading" function
where i doing a mistake please Help me
Here is my code
1. this is my background function each 30 sec its call webservices
- (void)applicationDidEnterBackground:(UIApplication *)application
{
if ([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)]) { //Check if our iOS version supports multitasking I.E iOS 4
if ([[UIDevice currentDevice] isMultitaskingSupported]) { //Check if device supports mulitasking
UIApplication *application = [UIApplication sharedApplication]; //Get the shared application instance
__block UIBackgroundTaskIdentifier background_task; //Create a task object
background_task = [application beginBackgroundTaskWithExpirationHandler: ^ {
[application endBackgroundTask: background_task]; //Tell the system that we are done with the tasks
background_task = UIBackgroundTaskInvalid; //Set the task to be invalid
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Perform your tasks that your application requires
while(TRUE)
{
//backgroundTimeRemaining time does not go down.
// NSLog(#"Background time Remaining: %f",[[UIApplication sharedApplication] backgroundTimeRemaining]);
[UIApplication sharedApplication].applicationIconBadgeNumber++;
NSLog(#"\n\nRunning in the background!\n\n");
[self CallWebservices2];
[NSThread sleepForTimeInterval:30]; //wait for 1 sec
}
[application endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
});
}
}}
2.this is my call webservices, this code reach to CallWebservices2 function but no able to call connectionDidFinishLoading
-(void)CallWebservices2
{
NSString *urlString = [NSString stringWithFormat:#"http://yournurses.com/process/push.php?action=select_jobs&id=241"];
NSLog(#"String Url = %#",urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSURLConnection *connnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
[connnection start];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"Error==%#",error);
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
[nsUrlResponseDataNurse setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[nsUrlResponseDataNurse appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if ([nsUrlResponseDataNurse length]==0)
{}
else{
NSString *str = [[NSString alloc]initWithData:nsUrlResponseDataNurse encoding:NSUTF8StringEncoding];
allDataNurse = [str JSONValue];
NSLog(#"%#",allDataNurse);
}
}
here i define in delegate.h file
#property(nonatomic,retain)NSMutableData *nsUrlResponseDataNurse;
#property(nonatomic, retain) NSMutableArray *allDataNurse;
Regards,
Nishant Chandwani
NSURLConnection supports async network transactions "out of the box". You should not run NSURLConnection from the background. It is pointless and wasteful. The class is designed to handle background downloading efficiently.
You create an NSURLConnection on the main thread and start it running. It does it's work in the background, then calls your delegate methods on the main thread.
If you only need to get notified when the download/PUT is complete, you can use the NSURLConnection class method sendAsynchronousRequest:queue:completionHandler: which runs the whole request, then calls your completion handler once it's done. Generally you have that method call your completion handler on the main queue, since that code gets called once the URL request is finished.
Your code might look like this:
NSURL *url = [NSURL URLWithString: #"http://www.foo.php"];
NSURLRequest *request = [NSURLRequest requestWithURL: url];
[NSURLConnection sendAsynchronousRequest: request
queue: [NSOperationQueue mainQueue]
completionHandler: ^(NSURLResponse *response,
NSData *data,
NSError *connectionError)
{
if (data.length > 0 && connectionError == nil)
{
//The data for the response is in "data" Do whatever is required
}
}
];
That code will run the request in the background, and invoke the code in the completion block once it's finished. Simple and painless.
Asynchronous NSURLConnection call doesn't work in different runloop but mainRunLoop. Either use synchronous request in a different thread like :-
-(void)CallWebservices2
nsUrlResponseDataNurse = [NSURLConnection sendSynchronousRequest: returningResponse: error:]
}
, or if you badly want to make your code working, change the calls to :
[[NSURLConnection alloc] initWithRequest:urlRequest delegate:self startImmediately:NO];
[connnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
After I have read the answer for this question I have found that using reachabilityWithHostName does not work with a URL such as this one: mySite.com/service.asmx , is there anyway to check reachability against this URL using reachabilityWithHostName or any reachability class method ?
thanks so much in advance.
The Reachability class and -reachabilityWithHostname: is designed to be a quick, fail-fast mechanism to determine whether you have basic network connectivity to the host. If you need to verify that a particular URL can be downloaded, you need to be looking at using NSURLConnection to retrieve the contents of the URL in order to verify that it is truly available.
Depending on whether you need to do this in the foreground or background, you can either use the simple-but-blocking:
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error
or you can use the more complicated method of creating an NSURLConnection object, setting up a delegate to receive responses and wait for those responses to come in.
For the simple case:
NSURL *myURL = [NSURL URLWithString: #"http://example.com/service.asmx"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: myURL];
[request setHTTPMethod: #"HEAD"];
NSURLResponse *response;
NSError *error;
NSData *myData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];
If you receive back a non-nil myData, you've got some kind of connectivity. response and error will tell you what the server responded to you (in the case of response and if you received a non-nil myData) or what kind of error occurred, in the case of a nil myData.
For the non-trivial case, you can get good guidance from Apple's Using NSURLConnection.
If you don't want to stall your foreground process, you can do this two different ways. The above documentation will provide information on how to implement the delegate, etc. However, a simpler implementation would be to use GCD to send the Synchronous request on a background thread, and then message yourself on the main thread when you are done.
Something like this:
NSURL *myURL = [NSURL URLWithString: #"http://example.com/service.asmx"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: myURL];
[request setHTTPMethod: #"HEAD"];
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, NULL), ^{
NSURLResponse *response;
NSError *error;
NSData *myData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];
BOOL reachable;
if (myData) {
// we are probably reachable, check the response
reachable=YES;
} else {
// we are probably not reachable, check the error:
reachable=NO;
}
// now call ourselves back on the main thread
dispatch_async( dispatch_get_main_queue(), ^{
[self setReachability: reachable];
});
});
If you want to check reachability against a URL (the one usually used is against a hostname) just do a HEAD request using a NSURLConnection.
Swift 5
A possible solution for Swift is:
func verifyURL(urlPath: String, completion: #escaping (_ isValid: Bool) ->()) {
if let url = URL(string: urlPath) {
var request = URLRequest(url: url)
request.httpMethod = "HEAD"
let task = URLSession.shared.dataTask(with: request) { _, response, error in
if let httpResponse = response {
if httpResponse.getStatusCode() == 200 {
completion(true)
}
} else {
completion(false)
}
}
task.resume()
} else {
completion(false)
}
}
Then call the method like that:
verifyURL(urlPath: "www.google.com", completion: { (isValid) in
if isValid {
runYourCode()
} else {
print("URL: www.google.com is not reachable")
}
})
I am aware of discussions regarding nsurlconnection on ios, and that there is a minimum of 240 seconds for a timeout. My question is, if I am sending a synchronous call via NSURLConnection's + (NSData *)sendSynchronousRequest:(NSURLRequest )request returningResponse:(NSURLResponse *)response error:(NSError **)error, is there any chance I can cancel this before the 240 seconds is up? I am thinking perhaps setting a timer to cancel this synchronous request, but im not even sure if its even possible? Im thinking:
[self performSelector:#selector(cancelRequest:) withObject:myRequest afterDelay:myTimeOut];
I have a feeling this will result in disaster if somehow the request has been released, and I would have no way to determine that. Thoughts? Has anyone tried to do this? This is a synchronous call.
You cannot cancel it. Simply don't use it and use an asynchronous call instead. Those you can easily cancel.
This seemed to work for me:
NSURL *url = [NSURL URLWithString:#"http://someurl.com"];
NSURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5];
NSHTTPURLResponse *response = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
if (response == nil) {
// timed out or failed
} else {
// all good
}
Ofcourse setting the timeout interval to how long you want it to block the main thread before timing out - The above code successfully timed out after 5 seconds
Tested in iOS6 & iOS5.1
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];
webData = (NSMutableData *)[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
if (webData==nil) {
[self displayAlert:#"Time Out" message:#"Request Timed Out"];
}
Timeout in exactly 10 seconds.