IOS: Using stringWithContentsOfURL when network is unavailable - ios

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.

Related

STOMP Websocket sometimes doesn't response

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!

Saving PFFile Eventually

A PFObject can be saveEventually to be sync on Parse when network is reachable, while keeping it locally meanwhile.
If your file contains a PFFile, the file must be savedInBackground before your PFObject can be save.
How to saveEventually a PFFile, for it to be send now, or later when network is reachable ?
As you might know, that feature isn't available within ParseSDK, so after seeing a few posts vaguely explaining how to bypass this, I wrote a sample working XCode project
That's only a working PoC with limitations such as only working for a single Parse class to associate saved PFFile on.
It requires Reachability pod 'Reachability', '~> 3.2'
How to use it ? Well, I guess the sample projects describes it well, but here is a piece of code to understand how it works :
(Remember to run pod install to resolve dependencies before running example)
/*
This example uses an UIImage, but this works with any file writable as NSData
We begin by writing this image in our tmp directory with an uuid as name.
*/
UIImage *nyancat = [UIImage imageNamed:#"nyancat.jpg"];
NSData *imageData = UIImageJPEGRepresentation(nyancat, 0.5);
NSString *filename = [[NSUUID UUID] UUIDString];
NSURL *fileUrl = [PFFileEventuallySaver fileURLInTmpWithName:filename];
[imageData writeToURL:fileUrl atomically:YES];
/*
We create a PFObject (you can pass an array to below function if you need your file to be saved on several objects). If upload works on first time, do what you want with your file, like linking it on your PFobject.
If saving fails, it'll be retried as soon as network is available, on this session or nexts launches of app.
In that case, the pointer at key kPFFILE_MANAGER_OBJECT_FILE_KEY of your PFFObject will be set with the PFFile, then saved eventually within PFFileEventuallySaver
*/
PFObject *object = [PFObject objectWithClassName:kPFFILE_CONTAINER_OBJECT_CLASSNAME];
[[PFFileEventuallySaver getInstance] trySaveobjectAtURL:fileUrl associatedObjects:#[object] withBlock:^(PFFile *file, NSError *error) {
if(!error)
{
NSLog(#"[First try, network is fine] File saved, saving PFObject");
object[kPFFILE_MANAGER_OBJECT_FILE_KEY] = file;
[object saveEventually];
NSLog(#"Try again disabling your network connection");
}
else
{
NSLog(#"No network, connect back your wifi, or relaunch app. Your file will be sent");
}
} progressBlock:^(int percentDone) {
NSLog(#"[First try, network is fine] Sending file %d/100%%", percentDone);
}];
This could be greatly improved, but I thought you guys might found that useful, as I would've wanted to find a similar working example.

How to read content from plain text remote file with objective-c

I want to read a list (in plain text) from a remote file line by line.
I have found some answers but they're not the ones I'm looking for.
p.s. I've been programing in objective-c and developing in iOS for about 2 months, I'm a rookie i might not understand or recognize some terms. Please answer like you are talking to a beginner.
If i am not wrong you just want to read a text from remote file, so here it is.
NSString * result = NULL;
NSError *err = nil;
NSURL * urlToRequest = [NSURL URLWithString:#"YOUR_REMOTE_FILE_URL"];//like "http://www.example.org/abc.txt"
if(urlToRequest)
{
result = [NSString stringWithContentsOfURL: urlToRequest
encoding:NSUTF8StringEncoding error:&err];
}
if(!err){
NSLog(#"Result::%#",result);
}
To load the remote txt file, you should take a look at NSURLConnection or AFNetworking (there are other possibilities, these two are probably the most common).
You will then get the content of the file. Depending on what you intend to do with it, you may have to parse it, either with something as simple as -[NSString componentsSeparatedByString:] or with something a bit more powerful like NSScanner.
There are three steps involved in loading a file
create the object that specifies the location of the file
call the appropriate NSString class method to load the file into a
string
handle the error if the file is not found
In step 1, you need to either create an NSString with the full path to the file in the file system, or you need to create an NSURL with the network location of the file. In the example below, the code creates an NSURL since your file is on the network.
In step 2, use the stringWithContentsOfFile method to load a file from the file system, or the stringWithContentsOfURL method to load a file from the network. In either case, you can specify the file encoding, or ask iOS to auto-detect the file encoding. The code below auto detects while loading from the network.
In step 3, the code below dumps the file to the debug console if successful or dumps the error object to the console on failure.
Missing from this code is multithreading. The code will block until the file is loaded. Running the code on a background thread, and properly notifying the main thread when the download is complete, is left as an exercise for the reader.
NSURL *url = [NSURL URLWithString:#"www.example.com/somefile.txt"];
NSStringEncoding encoding;
NSError *error;
NSString *str = [NSString stringWithContentsOfURL:url usedEncoding:&encoding error:&error];
if ( str )
NSLog( #"%#", str );
else
NSLog( #"%#", error );

NSURLConnection always failing after restarting app

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

How to purge / flush cache of NSString

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?

Resources