Currently I am doing simple tests of my app (written in xCode for MAC OS X) and I noticed that there are some issues when it comes to getting data from internet. So I am requesting some text data:
NSString *dataFromInternet = [[NSString alloc] initWithContentsOfURL:url
usedEncoding:&encoding
error:&error];
Now:
If internet works then everything is awesome.
If internet disconnected then I am getting error in "error" however "dataFromInternet" still returns the very same data as if there was internet connect
If I request data (above code) while internet disconnected and then connect internet and request data once again, I am still getting error as if internet doesn't work!
I don't understand this behavior and what is going on. I can only guess there is some caching mechanism and I don't now how to fix it.
Please explain this ( #2 & #3 ) odd behavior and how to fix it.
Thank you.
Okay, so after sometime roaming around internet and trying to find answer to my question, here is what I came up with:
NSString *dataFromInternet = [[NSString alloc] initWithContentsOfURL:url
usedEncoding:&encoding
error:&error];
Above code does seem to use cache. In order to get data from internet and not to have all issues that are posted in the question, you have to use different object.
NSData* data = [[NSData alloc] initWithContentsOfURL:url options:NSUncachedRead error:&error];
NSString *dataFromInternet = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
What is happening in above sample code? You get data from internet almost the same way as you would with NSString except you specify following: "options:NSUncachedRead" - meaning that it will not cache the data and read always the latest and greatest - under condition that internet works.
Once you obtained data you can convert it into NSString if desirable. I needed NSString so I converted it back to what I want. Otherwise all of issue in original post are solved!
I can turn off airport on my mac and no data will be received and as soon as I turn on airport, data is flowing again. Very simple and works great for me.
Thank you.
So I'm not able to repro this. With this code:
NSError *error = nil;
NSStringEncoding encoding = 12345678; // known bad value
NSString *test = [[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://www.example.com/non-existant-page.html"] usedEncoding:&encoding error:&error];
if (test == nil) {
NSLog(#"didnt work:%#, enc=%d, error:%#",test, encoding, error);
} else {
NSLog(#"worked:%#, enc=%d, error:%#", test, encoding, error);
}
... and without internet, I get this:
2011-08-28 22:30:45.482 test[48578:207] didnt work:(null), enc=12345678, error:Error Domain=NSCocoaErrorDomain Code=256 "The operation couldn’t be completed. (Cocoa error 256.)" UserInfo=0x5b09280 {NSURL=http://www.example.com/non-existant-page.html}
I also ran this after doing it with internet to confirm that it wasn't being cached (it isn't), so I don't see how you could have gotten a result. Can you give us more of the code that you used?
Related
I have a service using STOMP Websocket, I use WebsocketStompKit library
https://github.com/rguldener/WebsocketStompKit
NSURL *websocketUrl = [NSURL urlWithString:#"ws://xxx/websocket"];
STOMPClient *client = [[STOMPClient alloc] initWithURL:websocketUrl websocketHeaders:nil useHeartbeat:NO];
[self.client connectWithHeaders:nil completionHandler:^(STOMPFrame *connectedFrame, NSError *error) {
NSString *status = [Utils getStringIgnoreNull:connectedFrame.command];
if ([status isEqualToString:#"CONNECTED"]) {
NSLog(#"-------Connected to socket server!");
[self subscribe];
}
}];
I followed the instructions to setup STOMPClient, it works ok.
But sometime, it doesn't run to completionHander block, I waited a long time but it still don't response anything. My internet connection is very fine.
So anyone know the solution? Or can you give me another library to do this.
Thank so much.
As it turned out in this and this Github issue conversations, the problem was on the server side. If anyone comes here looking for help, I suggest going through these libraries issue pages and trying to match your problem, or contact the creators of Jetfire and Starscream (if you are implementing them) because they are very friendly and do answer your upgrade/new feature issues pretty quickly!
I have A NSdata value that it needs to be converted into a string.
So far my app works fine loading a QC composition from a server however, I have a warning when I tell QC to load data from server.
It loads the file just fine but is there a way to avoid this worming?
I have tried to convert data to string using
NSString* newStr = [[NSString alloc] initWithData:urlData
encoding:NSUTF8StringEncoding];
HOwever, it is giving a null location of the file
Find the way I was loading the file with wrong method the correct one is:
QCComposition *qc = [QCComposition compositionWithData:urlData];
Let me start off by saying that I am not particularly trying to find a solution, just the root cause of the problem. I am trying to retrieve a JSON from a url. In browser, the url call works just fine and I am able to see the entire JSON without issue. However, in x-code when simply using NSURLConnection, I am getting data bytes, but my NSString is null.
theString = [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
After doing some research I have found that I am probably trying to use the wrong encoding. I am not sure what type of encoding is being used by the url, so on first instinct I just tried some random encoding types.
NSString* myString = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSString* myString2 = [[NSString alloc] initWithData:data encoding:NSUTF16StringEncoding];
NSString* myString3 = [[NSString alloc] initWithData:data encoding:NSWindowsCP1252StringEncoding];
NSASCIIStringEncoding and NSWindowsCP1252StringEncoding is able to bring back a partially correct JSON. It is not the entire JSON thatI am able to view in the browser, and some characters are a little messed up, but it is something. To try and better determine what encoding was used, I decided to use the following method to try and determine it by looking at what encoding returned.
NSError *error = nil;
NSStringEncoding encoding;
NSString *my_string = [[NSString alloc] initWithContentsOfURL:url
usedEncoding:&encoding
error:&error];
My NSStringEncoding value is 3221214344. And this number is consistent everytime I run the app. I can not find any NSStringEncoding values that even come close to matching this.
My final question is: Is the encoding used for this url not consumable by iOS, is it possible that multiple types of encoding was used for this url, or is there something else that I could be doing wrong on my end?
It's best not to rely on Cocoa to figure out the string encoding if possible, especially if the data might be corrupted. A better approach would be to check if the value indicated by the HTTP Content-Type header specifies a character set like in this example:
Content-Type: text/html; charset=ISO-8859-4
Once you're able to parse and retrieve a character set name from the Content-Type header, you need to convert it to an NSStringEncoding, first by passing it to CFStringConvertIANACharSetNameToEncoding, and then passing the returned CF string encoding to CFStringConvertEncodingToNSStringEncoding. After that, you can initialize your string using -[NSString initWithData:encoding:].
NSData *HTTPResponseBody = …; // Get the HTTP response body
NSString *charSetName = …; // Get a charset name from the Content-Type HTTP header
// Get the Core Foundation string encoding
CFStringEncoding cfencoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)charSetName);
// Confirm this is a known encoding
if (cfencoding != kCFStringEncodingInvalidId) {
// Initialize the string
NSStringEncoding nsencoding = CFStringConvertEncodingToNSStringEncoding(cfencoding);
NSString *JSON = [[NSString alloc] initWithData: HTTPResponseBody
encoding: nsencoding];
}
You still may run into problems if the string data you're working with is corrupted. For example, in the above code snippet, perhaps charSetName is UTF-8, but HTTPResponseBody can't be parsed as UTF-8 because there's an invalid byte sequence. In this situation, Cocoa will return nil when you try to instantiate your string, and short of sanitizing the data so that it conforms to the reported string encoding (perhaps by stripping out invalid byte sequences), you may want to report an error back to the end user.
As a last-ditch effort — rather than reporting an error — you could initialize a string using an encoding that can handle anything you throw at it, such as NSMacOSRomanStringEncoding. The one caveat here is that unicode / corrupted data may show up intermittently as symbols or unexpected alphanumerics.
Even though it seems that the answer has been provided in the comments (using iso-8859-1 as the correct encoding) I thought it worthwhile to discuss how I would go about debugging this problem.
You said that the Desktop Browser (Chrome) can digest the data correctly, so let's use that:
Enable Developer Tools https://developers.google.com/chrome-developer-tools/
When the Dev Tools window is open, switch to "network" and execute your call in that browser tab
check the output by clicking on the request url - it should give you some clue.
If that doesn't work, tools like Postman can help you to recreate the call before you implement it on the device
I realize this is a vague question, but I'm wondering if anyone else has observed this. Here is my code for calling the NSURLConnection
// Get data from server
NSString *host = #"www.hostname.com";
NSString *urlString = [NSString stringWithFormat:#"/theRestOfTheURL"];
NSURL *url = [[NSURL alloc] initWithScheme:#"http" host:host path:urlString];
DLog(#"URL is %#", url);
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData_ = [[NSMutableData data] retain];
NSURLRequest *theRequest=[NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:15.0];
// create the connection with the request
// and start loading the data
self.powerPlantDataConnection = [[[NSURLConnection alloc] initWithRequest:theRequest delegate:self] autorelease];
[url release];
When I first load the app it works fine, and I can call it repeatedly without any problem. But if I close the app and reopen it, the
(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
delegate method gets called every time, with a request timed out error message. I have two different view controllers where I am making calls to two different URLS, and both of them fail every time after closing and reopening the app.
Can anyone think of any reason why this might be happening? I'm not sure where to start looking. What could be the cause of a request timed out error? There should be nothing wrong with the request since it works when I first run the app.
Edited to add that it seems I only have this problem on my device, not on the simulator.
Wish you had shared some chrash log(especially with clear definition like
[error localizedDescription] class method..)
As you have said it is going to timeout(your request). and since your way of creating the objects is too messy, you make the work bigger for your system. I suggest using GCD when downloading data and especially in situations like yours, having different interfaces and urls..
A suggestion
You can create your url object like this:
NSURL *url = [NSURL urlWithString:[NSString stringWithFormat:#"http://%#/%#?key1=%#&key2=%#", yourDomain, targetFile, value1, value2]];
I switched over to using ASIHTTPRequest, which improved things but I would still get stuck in situations where I was getting timed out errors every time I tried to refresh. I looked and asked around, and eventually found that disabling calls to TestFlight solved my issue. More information here:
ASIHTTPRequest request times out
and here:
github.com/pokeb/asi-http-request/issues/320
In this code poll from within my app for a reachable network
("http://soxxx9.cafe24.com/event.php")
NSString * szURL =[NSString stringWithFormat:#"http://soxxx9.cafe24.com/event.php"];
NSURL *url = [NSURL URLWithString:[szURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding ]];
NSString *strData;
while(1)
{
NSError *error = nil;
strData = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding
error:&error];
if(!error)
break;
//String data is not owned by me, no need to release
}
If you have a better way, please teach me.
This code seems to be heavily power consuming when network is out : you'll try million times to download something that is unreachable...
Have a look at the Reachability class, provided by Apple (http://developer.apple.com/library/ios/#samplecode/Reachability/Introduction/Intro.html). You'll find ARCified versions on gitHub (https://github.com/tonymillion/Reachability for example).
The idea is to register for notifications about the network reachability.
So, in your code :
Check network resource availability before retrieving the string you want.
If this is available, use your code WITHOUT the while(TRUE)
Check your string for any error while retrieving it client side = in your code
If the network is not available, you'll have to inform the user that network is unreachable, and register for reachability notifications to retrieve your string as soon as it is reachable again for example.
You should a class to handle the connection for you. This way you have more control of what's going on with it. MKNetworkKit is a solution, you can check it here.