Different NSString results from URL download - ios

I am parsing a string that I obtain from a website but get different results depending on how I download.
This way it works:
NSString *tagiString = #"http://tagesanzeiger.ch";
NSURL *tagiURL = [NSURL URLWithString:tagiString];
NSError *error;
NSString *text =[NSString stringWithContentsOfURL:tagiURL
encoding:NSASCIIStringEncoding
error:&error];
Te following way it does not work. I first download the data, feed it into the NSMutableData *articleData and then convert to a NSString with initWithData:encoding:
- (void)downloadWebsite
{
NSString *tagiString = #"http://tagesanzeiger.ch";
NSURL *websiteURL = [NSURL URLWithString:tagiString];
NSURLRequest *request = [NSURLRequest requestWithURL:websiteURL];
connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self
startImmediately:YES];
}
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
[articleData appendData:data];
}
- (NSString *)data
{
NSString *text = [[NSString alloc] initWithData:articleData
encoding:NSSymbolStringEncoding];
return text;
}
Seems like the resulting NSString *text content is not the same for both versions? Do I need to use a different string encoding? I have tried many without success.

Implement the delegate method connectionDidFinishLoading to ensure the connection loading has finished where you can call your data method. Also try to use NSASCIIStringEncoding instead of
NSSymbolStringEncoding.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *text = [[NSString alloc] initWithData:self.articleData
encoding:NSASCIIStringEncoding];
//do whatever you need to do with the text
}

Yes, you need to use a different string encoding. You can try NSUTF8StringEncoding. Here it's working for me. And utf-8 is almost the most popular encoding way.

Related

From NSURLConnection to NSURLSession

What is the best way to convert NSURLConnection to NSURLSession ?
error message: (Xcode)
ViewController.m:342:45: 'stringByAddingPercentEscapesUsingEncoding:' is deprecated: first deprecated in iOS 9.0 - Use -stringByAddingPercentEncodingWithAllowedCharacters: instead, which always uses the recommended UTF-8 encoding, and which encodes for a specific URL component or subcomponent since each URL component or subcomponent has different rules for what characters are valid.
my code :
-(void)downloadZip
{
NSLog(#"Start Downloading Zip File");
NSDate *myDate = (NSDate *)[[NSUserDefaults standardUserDefaults] objectForKey:#"LastUpdate"];
NSString *path = [NSString stringWithFormat:phpLinkgetZip, myDate];
NSURL *url = [NSURL URLWithString:[path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSLog(#"Checking update at Zip File : %#", path);
NSLog(#"Checking update Time : %#", myDate);
responseData = [[NSMutableData alloc] init];
NSURLRequest* updateRequest = [NSURLRequest requestWithURL: url];
NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:updateRequest delegate:self];
[connection start];
NSLog(#"Zip Downloading start...");
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
filesize = [[NSNumber numberWithLong: [response expectedContentLength] ] retain];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self updateZipDownloaded];
[filesize release];
[connection release];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
NSNumber* curLength = [NSNumber numberWithLong:[responseData length] ];
float progress = [curLength floatValue] / [filesize floatValue] ;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Zip Downloading error");
}
If you want to overcome above error please use below code
NSCharacterSet *setPath = [NSCharacterSet URLPathAllowedCharacterSet];
NSString *strURL = [path stringByAddingPercentEncodingWithAllowedCharacters:setPath];
stringByAddingPercentEncodingWithAllowedCharacters:
Returns a new string made from the receiver by replacing all
characters not in the specified set with percent-encoded characters.
Characters passed to set below methods
(NSCharacterSet *)URLUserAllowedCharacterSet;
(NSCharacterSet *)URLPasswordAllowedCharacterSet;
(NSCharacterSet *)URLHostAllowedCharacterSet;
(NSCharacterSet *)URLPathAllowedCharacterSet;
(NSCharacterSet *)URLQueryAllowedCharacterSet;
(NSCharacterSet *)URLFragmentAllowedCharacterSet;
If you want to go NSURLSession from NSURLConnetion,do the following things
NSURL *URL = [NSURL URLWithString:#"http://example.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
// ...
}];
[task resume];
NSURLSession class and related classes provide an API for downloading content via HTTP. This API provides a rich set of delegate methods for supporting authentication and gives your app the ability to perform background downloads when your app is not running or, in iOS, while your app is suspended.
To use the NSURLSession API, your app creates a series of sessions,
each of which coordinates a group of related data transfer tasks. For
example, if you are writing a web browser, your app might create one
session per tab or window. Within each session, your app adds a series
of tasks, each of which represents a request for a specific URL (and
for any follow-on URLs if the original URL returned an HTTP redirect).
Like most networking APIs, the NSURLSession API is highly
asynchronous. If you use the default, system-provided delegate, you
must provide a completion handler block that returns data to your app
when a transfer finishes successfully or with an error. Alternatively,
if you provide your own custom delegate objects, the task objects call
those delegates’ methods with data as it is received from the server
(or, for file downloads, when the transfer is complete).

Objective-C getting mime type of url file before webview loads it

I'm facing a problem building a web browser with download functionality, here's my code:
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *url = request.URL;
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:req delegate:self];
[conn start];
return YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if ([[response MIMEType] rangeOfString:#"video"].location != NSNotFound) {
// Do something with that video
}
}
This is currently working as intended, video files will be handled correctly but the webview will also load it, what i need to do is capture the mime type of the file before returning YES in shouldStartLoadWithRequest and return NO if it's a video.
I tried the sendSynchronousRequest method but it slows the app, I also tried:
#import <MobileCoreServices/MobileCoreServices.h>
NSString *fileExtension = [myFileURL pathExtension];
NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtension, NULL);
NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType);
But I often get wrong myme types, last thing, I dont want to detect type by the file extension since urls can be formatted as aliases.
Thank you for your help.
NSURLConnection is dead so stop using it. Switch to NSURLSession. NSURLSession gives you a data task delegate method that lets you examine the response header and bow out.

Pause a download in objective-c

I'm unsure of what the best approach is for pausing a download. I have seen this question asked on stack over flow before, but doesn't seem to achieve the results I am looking for. For example: I understand inside of the AppDelegate, the - (void)applicationWillResignActive:(UIApplication *)application is called if a phone call comes on the phone for example. It is crucial for my app to successfully download the database to function appropriately. Here's the code I use to download the database:
NSString *urlDb = [NSString stringWithFormat:#"someURl'];
//---Create URL from where DB has to be download-----
NSURL *url = [NSURL URLWithString:urlDb];
NSError *error = nil;
NSData *data = [NSData dataWithContentsOfURL:url options:0 error:&error];
Pausing a download may not be critical for example, AT&T, but folks with Verizon cannot talk and download at the same time. Any help would be greatly appreciated. Thanks!
If you want pause/resume functionality, then you must use either old NSURLConnection, and implement all required delegate methods, or you can use new NSURLSession API.
Here is a basic implementation with NSURLConnection:
#property NSFileHandle *fileHandle;
#property NSURLConnection *connection;
// start download
- (IBAction)downloadButtonPressed
{
NSURL *url = [NSURL URLWithString:#"myUrl"];
NSURLRequest *dataRequest = [NSURLRequest requestWithURL:url];
self.connection = [NSURLConnection connectionWithRequest:dataRequest delegate:self];
[connection start];
}
Implement delegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:#“pathToYourFile”];
[self.fileHandle seekToEndOfFile];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.fileHandle writeData:data];
}
If you want to pause - just cancel connection like this:
[self.connection cancel];
Then you can resume like this:
- (void)resumeDownload
{
NSURL *url = [NSURL URLWithString:#"myUrl"];
NSMutableURLRequest *dataRequest = [NSMutableURLRequest requestWithURL:url];
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:pathToYourFile error:&attributesError];
NSNumber *fileSizeNumber = [fileAttributes objectForKey:NSFileSize];
NSString *bytesRangeHeader = [NSString stringWithFormat:#"bytes=%lld-", [fileSizeNumber longLongValue];
[_request setValue:bytesRangeHeader forHTTPHeaderField:#"Range"];
self.connection = [NSURLConnection connectionWithRequest:dataRequest delegate:self];
[connection start];
}

NSMutableData disappearing

in my Program, I have a NSMutableData variable that collect the information from http://www.nhara.org/scored_races-2013.htm. After about the third time it gets information from a website, when it contains 90810 bytes, it either disappears or becomes null because if I print it a NSString, it is null. Here is the code
- (void)viewWillAppear:(BOOL)animated
{
// Create a new data container for the stuff that comes back from the service
xmlData = [[NSMutableData alloc] initWithCapacity:180000];
[self fetchEntries];
[super viewWillAppear:animated];
}
- (void)fetchEntries
{
// Construct a URL that will ask the service for what you want
NSURL *url = [NSURL URLWithString: #"http://www.nhara.org/scored_races-2013.htm"];//
// Put that URL into an NSURLRequest
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Create a connection that will exchange this request for data from the URL
connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
}
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
// Add the incoming chunk of data to the container we are keeping
// The data always comes in the correct order
[xmlData appendData:data];
NSLog(#"%#",xmlData);
NSString *xmlCheck = [[[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding]autorelease];
NSLog(#"xmlCheck = %#", xmlCheck);
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"error= %#",error);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)conn {
// We are just checking to make sure we are getting the XML
NSString *xmlCheck = [[[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"xmlCheck2 = %#", xmlCheck);
}
What confuses me the most is that my NSMutableData stores data, but then loses it while claiming to have the same number of bytes.
Is there a constraint to the NSMutableData's size or is my problem just memory management?
You need to create a property for your xmlData variable. In your header file after your
#interface MyClass, make one like so
#property (nonatomic, retain) NSMutableData * xmlData;
If you are using ARC you leave it as strong if you using below ARC you change strong to retain. When you want to use your variable you do self.xmlData

Json Data in int format

I am parsing json and the url is returning an integer value. (e.g. 278)
-(void) connectionDidFinishLoading: (NSURLConnection *) connection{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSString *responseString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"JSON Response = %#",responseString);}
when I am printing response in NSLog, it gives out something like this
2012-09-15 18:02:02.091 Web Service[5190:f803] JSON Response = "278"
I don't want the output in quotes. I want it like
2012-09-15 18:02:02.091 Web Service[5190:f803] JSON Response = 278
how can i achieve this?
JSON
NSString *urlString = [NSString stringWithFormat:#"http://10.5.6.105/ARAPPWS/Service1/InsertEmp/name=%#,phone=%#",name.text,number.text];
NSURL *addUrl = [NSURL URLWithString:urlString];
NSURLRequest *addRequest = [NSURLRequest requestWithURL:addUrl];
(void)[NSURLConnection connectionWithRequest:addRequest delegate:self];
-(void) connection: (NSURLConnection *) connection didReceiveResponse:(NSURLResponse *)response
{
jsonData = [[NSMutableData alloc]init];
}
-(void) connection: (NSURLConnection *) connection didReceiveData:(NSData *)data
{
[jsonData appendData:data];
}
-(void) connectionDidFinishLoading: (NSURLConnection *) connection
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
responseString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[self performSelector:#selector(uploadEmpImg:) withObject:nil afterDelay:1];
}
Thanks in advance.
You can use - [NSString integerValue] to obtain the actual numerical representation of the string:
NSLog(#"JSON response = %d", [responseString integerValue]);
Edit: the problem is that it returns a JSON fragment - strictly speaking it's not valid JSON. You can then use
[responseString substringWithRange:NSMakeRange(1, responseString.length - 2)]
to get the actual string value without the quotes and
[[responseString substringWithRange:NSMakeRange(1, responseString.length - 2)] intValue]
to get it as an integer.

Resources