I need to check if a file exists on my server without using cache. The methods I have used are all returning a 200, even if the file does not exist, so I can only assume there is a cache problem, or theres a problem with my code.
Heres my code: for arguments sake..the URL is changed in this example, but the url is correct in my code.
NSString *auth = [NSString stringWithFormat:#"http://www.mywebsite.com/%#.txt",[self aString]];
NSURL *authURL = [NSURL URLWithString:auth];
NSURLRequest* request = [NSURLRequest requestWithURL:authURL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:5.0];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:request
delegate:self];
NSHTTPURLResponse* response = nil;
NSError* error = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"statusCode = %d", [response statusCode]);
if ([response statusCode] == 404)
NSLog(#"MISSING");
else
NSLog(#"EXISTS");
the response is always 200, even if I rename the file on the server.
There are a couple of potential problems with your code. First, when you create conn using connectionWithRequest:delegate: you are starting an asynchronous request. The response would be received in the delegate's (self in your case) connection:didReceiveResponse: method. Are you trying to do the request asynchronously? From the rest of your code though, it looks like you are actually trying to do a synchronous request. That's what sendSynchronousRequest:returningResponse:error: is for. If that's what you intend, then you don't need the earlier call to create a connection.
Assuming thats the case, you need to capture and check the value returned from calling sendSynchronousRequest:returningResponse:error:. It will return nil if the connection failed, which is what I suspect is happening. You can then look at the error returned to figure out what is going on. Try something like:
NSData * result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (result != nil) {
NSLog(#"statusCode = %d", [response statusCode]);
if ([response statusCode] == 404)
NSLog(#"MISSING");
else
NSLog(#"EXISTS");
} else {
NSLog(#"%#", error);
}
Is it possible it's caching on the server side? If so you could try NSURLRequestReloadIgnoringLocalAndRemoteCacheData instead of NSURLRequestReloadIgnoringCacheData.
Related
when i am running my app in the simulator everything is working perfectly .But when i running the same app in the Ipad exception is being thrown.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'data parameter is nil.
In my app at one step i have to request a web-URl and need to parsed the returned JSON response. But I have checked the web-url and have been able to parse perfectly in simulator. But all the problem has been arisen in real ios device.But I think i have identified the code where it is getting wrong.
+ (NSDictionary*) getParsedJSON:(NSString*) urlString {
NSLog(#"################################################################################");
NSLog(#"getParsedJSON => urlString:");
NSLog(#"%#", urlString);
NSURL* url = [NSURL URLWithString:urlString];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
NSURLResponse *response1 = nil;
NSError *error = nil;
NSData* response = [NSURLConnection sendSynchronousRequest:request returningResponse:&response1 error:&error];
//NSData* response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSLog(#"--------------------------------------------------------------------------------");
NSString* responseString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSLog(#"getParsedJSON => responseString:\n%#", responseString);
NSLog(#"--------------------------------------------------------------------------------");
NSError* jsonParsingError = nil;
NSDictionary* parsedJSON = [NSJSONSerialization JSONObjectWithData:response options:0 error:&jsonParsingError]; // here is place where exception seems to be thrown.
if (jsonParsingError) {
NSLog(#"ERROR in parsing JSON: %#", jsonParsingError);
} else {
NSLog(#"getParsedJSON => parsedJSON: \n%#", [parsedJSON description]);
}
NSLog(#"################################################################################");
return parsedJSON;
}
I have identified the line where it seems to be wrong .I have also attached screen shot of the exception report..Hoping for your experienced reply.
AS we can see from the logs your response string is null while you are using it on your Device. This may be due to some internet access problem. Try to Use:
if([response isequaltostring:#"(null)"]||response == nil || response.length == 0)
{
NSError* jsonParsingError = nil;
NSDictionary* parsedJSON = [NSJSONSerialization JSONObjectWithData:response options:0 error:&jsonParsingError]; // here is place where exception seems to be thrown.
if (jsonParsingError) {
NSLog(#"ERROR in parsing JSON: %#", jsonParsingError);
}
else {
NSLog(#"getParsedJSON => parsedJSON: \n%#", [parsedJSON description]);
}
}
Also try to add the exceptional breakpoint and post where exactly the app crashed.
Let me know the result.
First, you need to set an exception breakpoint in Xcode - there are many posts here on how to do that. Second, after each of you statements where an object is created or returned, add an assert:
NSURL *foo = ...
assert(foo);
Doing this will help you find the first issue not the last one.
As per your logs, your response string is empty!
Do the below two things!
Add NSLog(#"Response Data: %#",response); and check if the response has value?
If 'response' has value, convert it to a string - Log the string value - And check if the any of the key has nil value?
'NSJSONSerialization JSONObjectWithData' method would crash if it finds any key with nil value.
I'm using the following to request data using NSJSONSerialization. The problem I'm having is that if the data is inaccessible (e.g. no network connection) the app crashes. How could I go about stopping the app from crashing if the network or server is down?
I'm calling [self requestData]; in the viewDidLoad: method
-(void)requestData {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL
URLWithString:#"http://example.com/api/nodes"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSError *jsonParsingError = nil;
NSDictionary *publicData = [NSJSONSerialization JSONObjectWithData:response
options:0
error:&jsonParsingError];
publicDataArray = [publicData objectForKey:#"data"];
for(publicDataDict in publicDataArray) {
NSLog(#"data output is %#",[publicDataDict objectForKey:#"title"]);
}
}
thanks for any help
Some thoughts:
Use Reachability for checking network connection
Always use asynchronous request, else it'll block your UI till the app get the response from server.
Always use exception handling
Here the issue is:
You are calling a synchronous request in the viewDidLoad using sendSynchronousRequest. But the server is down, so you won't get the result, and it still expect any data to come. But your app won't load untill that request finishes. Due to this springboards application-watchdog will terminate your app.
What is Watch dog ?
watchdog — In order to keep the user interface responsive, iOS
includes a watchdog mechanism. If your application fails to respond to
certain user interface events (launch, suspend, resume, terminate) in
time, the watchdog will kill your application and generate a watchdog
timeout crash report. The amount of time the watchdog gives you is not
formally documented, but it's always less than a network timeout.
Please check this Technical question on Apple site.
Why don't you check if [NSURLConnection sendSynchronousRequest:] got any error?
NSError *requestError = nil;
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&requestError];
if (requestError)
{
NSLog(#"sync. request failed with error: %#", requestError);
}
else
{
// handle data
}
And you really should check if NSJSONSerialization had an error too:
NSError *jsonParsingError = nil;
NSDictionary *publicData = [NSJSONSerialization JSONObjectWithData:response
options:0
error:&jsonParsingError];
if (jsonParsingError)
{
NSLog(#"JSON parsing failed with error: %#", jsonParsingError);
}
else
{
// do something
}
I wonder how I can check if a file exist on a server or not, without downloading the data first.
I have around 30 different objects and some of them is connected to a movie on a server. At the moment I use NSData to control if the the URL exist, and then shows the movie, or if it doesn't and then alerts the user that there is no video for that object. The code I use for the moment:
NSString *fPath = [[NSString alloc] initWithFormat:#"http://www.myserver/%#", [rows idNr]];
NSURL *videoURL = [NSURL URLWithString:fPath];
NSData *videoData = [NSData dataWithContentsOfURL:videoURL];
url = [NSURL URLWithString:fPath];
[fPath release];
if (videoData) {
[self performSelectorOnMainThread:#selector(playVideo:) withObject:url waitUntilDone:NO];
} else {
NSLog(#"videodata false");
errorLabel.hidden = NO;
activityView.hidden = YES;
}
"rows idNr" is the name of the object. This method is doing what I want, but the problem is that with NSData it first "downloading" the file, and when the URL is validated as a file, the movie is loading once again in the movieplayer. This means that it takes twice as long to load the file.
Suggestions?
It took me a while to dig out my answer to one of the previous questions on this topic. Quote:
You can use a NSMutableURLRequest to send a HTTP HEAD request
(there’s a method called setHTTPMethod). You’ll get the same
response headers as with GET, but you won’t have to download the whole
resource body. And if you want to get the data synchronously, use the
sendSynchronousRequest… method of NSURLConnection.
This way you’ll know if the file exists and won’t download it all if it does.
Make an URLConnecion object with desired url request and add NSURLConnectionDelegate into .h file like I want to check "yoururl" is exist or not then you need to do is
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString: #"http://www.google.com"]];
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
and then you can track http status code in delegate function of NSURLConnectionDelegate
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
int code = [(NSHTTPURLResponse *)response statusCode];
if (code == 404)
{
// website not found
// do your stuff according to your need
}
}
You can also find various status code here.
NSError *err;
if ([videoURL checkResourceIsReachableAndReturnError:&err] == NO)
NSLog(#"wops!");
Here's the code for the accepted answer (for your convenience):
How to make call
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"HEAD"];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
You could do this by checking the size of the file via an FTP server, using the SIZE command. If the file size is zero then the file simply do not exist.
Check here on how to do this.
You could of course also do this by using a NSURLRequest with NSURLConnection, checking for the status to be either 200 (success) or 404 (failed). The 404 status doesn't have to be that the file doesn't exist though, it could also be that the file just couldn't be retrieved.
I am sending an http request from iOS (iPad/iPhone) to my python google app engine server using the NSURLConnection and NSURLRequest classes.
How do I read the response's status, i.e. the value set by app engine using response.set_status(200, message="Success") for instance?
I'm not able to find where I can read these status codes once I receive the NSURLConnection's connectionDidFinishLoading delegate call on the client end.
If you are sending a synchronous request, you could get the response code from NSHTTPURLResponse.
NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:URL_LOGIN]];
NSData *respData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"~~~~~ Status code: %d", [response statusCode]);
Hope this will help you :)
The connection:didReceiveResponse: delegate method is called when a response is received, which gives you an NSURLResponse to play with.
If you've made an HTTP request, then it'll actually be an NSHTTPURLResponse object, which has a statusCode method.
Whats the best way to make this a more secure and less obvious security risk?
NSString *loginIdentification = [NSString stringWithFormat:#"user=%#&pass=%#&", userNameLogin, passWordLogin];
addressVariable = [NSString stringWithFormat:#"%#/%#", url, loginIdentification];
addressVariable = [addressVariable stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
NSURLResponse* response = nil;
NSError* error = nil;
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
Make sure you're using an https connection and not an http connection.
Instead of putting the sensitive information in the URL (via GET), use the POST method and put them in the body. That way, they won't show up in your server logs.