Is there any resource efficient way (something that does not tie up the main thread) in IOS to check the existence of a remote file?
I have user images stored on a server. While there is a consistent url scheme, some images are .jpg, others are .gif, etc. so to get the correct image name, I need to check does user/file.gif exist, user/file.jpg exist etc. in order to download the file to the IOS app.
I found this code in another answer in IOS
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"HEAD"];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
But I am not sure how to use it. Ideally, I would like to get a boolean yes or no as to whether the .gif file exists, the .jpg file exists etc for the users profile pic so I can fill in the correct name to download the user pic.
The alternative would be to write a service on the back end to return the file but wondering if it can all be done in IOS.
Thanks for any suggestions.
**Use this function below to check whether file exists at specified url**
+(void)checkWhetherFileExistsIn:(NSURL *)fileUrl Completion:(void (^)(BOOL success, NSString *fileSize ))completion
{
//MAKING A HEAD REQUEST
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fileUrl];
request.HTTPMethod = #"HEAD";
request.timeoutInterval = 3;
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
if (connectionError == nil) {
if ((long)[httpResponse statusCode] == 200)
{
//FILE EXISTS
NSDictionary *dic = httpResponse.allHeaderFields;
NSLog(#"Response 1 %#",[dic valueForKey:#"Content-Length"]);
completion(TRUE,[dic valueForKey:#"Content-Length"]);
}
else
{
//FILE DOESNT EXIST
NSLog(#"Response 2");
completion(FALSE,#"");
}
}
else
{
NSLog(#"Response 3");
completion(FALSE,#"");
}
}];
}
Related
I need to load big image from thumbnail url with forHTTPHeaderField and cache it so that not to load again and again from url. Below is the code I am using.
NSString *urlStr = [NSString stringWithFormat:#"%#",medialurl];
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"GET"];
[request setURL:url];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"abcd" forHTTPHeaderField:#"ABC"];
[request addValue:#"xyzzy" forHTTPHeaderField:#"XYZ"];
[RestService fetchDataWithCompletionBlock:request completionHandler:^(NSData * _Nonnull responseData, NSURLResponse * _Nonnull response, NSError * _Nonnull error) {
NSString *responseStr = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"responseStr: %#", responseStr);
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
long code = (long)[httpResponse statusCode];
NSLog(#"response status code: %ld", code);
completionBlock(responseData);
}];
Would setting a different cachePolicy on your request help?
request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;
Use existing cache data, regardless or age or expiration date, loading from originating source only if there is no cached data.
There is a note on the cachePolicy property which states:
This property is ignored for requests used to construct NSURLSessionUploadTask and NSURLSessionDownloadTask objects, as caching is not supported by the URL Loading System for upload or download requests.
So, if that is how you're performing your request, this might not work and you would probably have to manage your caching for this request yourself.
You can check to see if there is a cached response for your request with the following (assuming you are using the shared cache and not creating your own):
NSCachedURLResponse* cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
if ( cachedResponse )
{
NSHTTPURLResponse* response = (NSHTTPURLResponse*)cachedResponse.response;
NSLog(#"Cached Response: %#", response.allHeaderFields);
}
else
{
NSLog(#"No Cached Response");
}
If your endpoint uses ETags, you can also store the value of the ETag header field from the cached response and then compare it to what you get back when you make your request, this would tell you if the response you get back was indeed from the cache or not.
If the above tells you there is no cached response for your request, then you'd have to look into why it might not be caching previous responses. Perhaps there is an issue with the "Cache-Control" header coming back from the server and you are not permitted to cache the responses? If that were the case and you have no control over the server side, you would have to use another method to cache your images.
I wanted to call SOAP services, saw many document's over link.
I used one of those like the BestSoaptool from github https://github.com/yillars/BestSoapToolwithafnet, but I am still lacking some where and not able to get the response.
I am using the link as -- "https://aaa.com/Customers.svc?singleWsdl" and then the method name "xxx" but I don't get a response.
If not this can any one give me some better idea as to how should I implement this?
Thanks.
I've added sample SOAP implementation in iOS in my wordpress blog. Hope this will help you https://wordpress.com/post/bharathreddys.wordpress.com/6
Lets assume the following .wsdl url is the source URL.
http://www.webservicex.net/geoipservice.asmx?WSDL
Create a SOAP Envelop and SOAP Header.
NSMutableString * soapHeader = #"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\""
" xmlns:hom=\"http://www.webservicex.net/">"
"<soapenv:Header/>";
Be remember that "xmlns:hom", text next to ":" is the word which will be used as the targetnamespace reference for the service call which will be added in SOAP body.
SOAP body will be as follows :
[soapHeader appendString:#"<soapenv:Body>"];
[soapHeader appendString:#"<hom:GetGeoIP>"]; // add the body parameters
[soapHeader appendString:#"<hom:IPAddress>0.0.0.1</hom:IPAddress>"];
[soapHeader appendString:#"</hom:GetGeoIP>"];
[soapHeader appendString:#"</soapenv:Body>"];
[soapHeader appendString:#"</soapenv:envelope>"];
Now the web service is as follows:
NSMutableString * requestStr = [NSMutableStringstring];
[requestStr appendString:soapHeader];
NSString * urlStr = #"http://www.webservicex.net/geoipservice.asmx?WSDL";
NSURL * url = [NSURL URLWithString:urlStr];
NSMutableURLRequest * request = [[NSMutableURLRequestalloc] initWithURL:url];
[request setValue:#"http://www.webservicex.net/GetGeoIP" forHTTPHeaderField:#"SOAPAction"];
[request setValue:#"http://www.webservicex.net/" forHTTPHeaderField:#"targetNamespace"];
[request setValue:#"text/xml;charset=UTF-8"forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:requestBody];
[request setHTTPMethod:#"POST"];
[request setValue:[NSStringstringWithFormat:#"%d",[requestBody length]] forHTTPHeaderField:#"Content-Length"];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
BOOL isSuccess = YES;
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSLog(#"received data---%#",response);
if(connectionError != nil) {
isSuccess = NO;
NSLog(#"connection error with code %d",connectionError.code);
}
NSDictionary * responseDictionary = [NSDictionary dictionary];
if([httpResponse statusCode] == 200) {
isSuccess = YES;
//Do something with the received dictionary.
}];
This is the basic platform how we can make a simple SOAP based web service calls in iOS.
Happy coding !!!!
I am making a simple web browser by using UIWebView. User enters an address on the address bar -> check it.
1.If the text is url -> load the request
2.If the text is string -> perform a google search
In the first case, if string has the format: abc.xyz, how to add a scheme and host to it?
Example: user enters google.com -> correct to https://google.com
engadget.com -> https://www.engadget.com.
My problem is how to know which part had to add to url(http, https, with or without www).
Update:
use NSURLSeassion to test connect
- (void)checkRequest:(NSString*)urlRequest
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlRequest]];
[request setHTTPMethod:#"HEAD"];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if (statusCode == 200)
NSLog(#"Correct url");
// check status code here
}
if (error) {
// handle other errors here
}
// handle data here
}];
[task resume];
}
Update 2
Don't need to check url, add http:// scheme and website will automatically redirect to the correct destination.
in your case i think you need to perform a HEAD request and check the result.
For example, with your sample url http://engadget.com. if it response not exists, add www to this url and try again.
NSMutableURLRequest request = [NSMutableURLRequest requestWithURL:inURL];
[request setHTTPMethod:#"HEAD"];
NSURLConnection connection = [NSURLConnection connectionWithRequest:request delegate:self];
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if ([(NSHTTPURLResponse *)response statusCode] == 200) {
// url exists
}
}
The url below downloads a file without an extention including busstations and times. The data is fetched in an iPhone-app that displays bustimes called mobitime. The problem is that I can't find out what encoding the data is. Is there any way to find out?
Thanks!
http://d2.mobitime.se/cgi/mtc/sad?uuid=01b07052fa390ceb845405e3d0547f7e&r=4&id=191430&no=721&to=Odensbacken%20via%20Ekeby-Almby&lang=sv
There are two techniques that I know of:
You can look at the HTTP headers and see if it reports anything useful:
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (id)response;
NSLog(#"httpResponse.allHeaderFields = %#", httpResponse.allHeaderFields);
}
}];
Those headers report "Content-Type" = "text/plain"; which obviously is not the case.
Sometimes you can also use the usedEncoding option of one of the initWithContentsOfURL method:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSStringEncoding encoding;
NSError *error;
NSString *string = [[NSString alloc] initWithContentsOfURL:url usedEncoding:&encoding error:&error];
if (error)
NSLog(#"%s: initWithContentsOfURL error: %#", __FUNCTION__, error);
if (string)
NSLog(#"encoding = %d", encoding);
});
But that reports an error (suggesting, again, that this might not be a string encoding at all).
In short, I'd suggest you contact the provider of that web service, and ask them regarding the format. But looking at the hex dump, I don't recognize the format. With a passing glance at it, it looks like binary data, not any string encoding.
I currently have a screen with 2 tables. I'm getting the data synchronously and putting it on the screen. Code looks something like:
viewController.m
DBAccess_Error_T = [getList:a byCompanyID:1];
DBAccess_Error_T = [getList:b byCompanyID:2];
[self putListAOnScreen];
[self putListBOnScreen];
DBAccess.m
+ (DBAccess_Error_T)getList:(NSMutableArray*)a byCompanyID:(NSInteger)cID
{
// Pack this up in JSON form
[self queryDB:postData];
// Unpack and put it into variable a
}
+ (id)queryDB:(id)post
{
// Send request
// Get back data
}
I'm now trying to switch this over to async and I'm struggling. It's been hard even with website tutorials and documentations.
Since all of my database utilities are in separate files from the viewControllers, I'm not sure how I can use the didReceiveData and didReceiveResponse handlers. Also, since I have 2 arrays to fill for my 2 tables, how do I distinguish the difference in didReceiveData?
Instead, what I'm trying to do now is use sendAsynchronousRequest, but it seems I need to create an unpack function for every send function...let me know if I'm way off here...it looks something like:
viewController.m stays the same
DBAccess.m
+ (DBAccess_Error_T)getList:(NSMutableArray*)a byCompanyID:(NSInteger)cID
{
NSDictionary *post = /*blah blah*/
[self queryDB:post output:(a)];
}
+ (id)queryDB:(id)post output:(id)output
{
NSError *error;
NSData *jsonPayload = [NSJSONSerialization dataWithJSONObject:post options:NSJSONWritingPrettyPrinted error:&error];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody:jsonPayload];
[NSURLConnection sendAsynchronousRequest:request
queue:[[NSOperationQueue alloc] init]
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error)
{
if ([data length] >0 && error == nil)
{
[self unpackDataForList:output data:data]; // This function needs to be different depending on which function called queryDB...the data will be unpacked in a different way
}
}
}
+ (void)unpackDataForList:(id)output data:(NSData*)data
{
// Do my unpacking here and stick it into 'output'.
}
How can I call a different unpackData function? are function pointers the right way to do this? Is this approach way off? Any tips would be greatly appreciated!
Have you ever looked at ASIHTTPRequest? It makes your life a lot easier by allowing you to use blocks. Here's an example of how to make an asynchronous request:
- (IBAction)grabURLInBackground:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://allseeing-i.com"];
__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setCompletionBlock:^{
// Use when fetching text data
NSString *responseString = [request responseString];
// Use when fetching binary data
NSData *responseData = [request responseData];
}];
[request setFailedBlock:^{
NSError *error = [request error];
}];
[request startAsynchronous];
}
You can find more information here:
http://allseeing-i.com/ASIHTTPRequest/