Does App WAIT for -initWithContentsOfURL: to retrieve web-data? - url

I am trying retrieve data from a .php file on a server from within an iPhone OS app. In one method, I employ the following code:
NSString *aString = [[NSString alloc] initWithContentsOfURL:aURL encoding:anEncoding error:nil];
//See what I got
NSLog(aString);
When I run the App it seems like the App runs through the code so fast I doubt that there was enough time for a Data Request to have transpired. The resulting string is totally empty, which further supports my suspicions. What is happening here? Is the app not waiting for the -initWithContentsOfURL to retrieve data from the .php file on my server? If the app does not wait for this method, is there another method I can use to perform a Data Request in a manner that WAITS for the request to be completed before moving onto the next code?
(I've also read a little on NSURLConnection -- is this maybe what I should be looking into instead of -initWithContentsOfURL?)

NSURLConnection is great for getting a file from the web... It doesn't "wait" per se but its delegate callbacks:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
...allow you to be notified when data has been received and when the data has been completely downloaded. This way you can have the App show (if you like) a UIProgressBar as the data comes in and then handle the file as you please when it is completely received.

Related

Asynchronous Values Update using GCDAsynSocket api

I am developing one application in which I need to update multiple values like Engine RPM,Speed etc. parameters at a time using OBD connector. I need to achieve asynchronous command/response . For this I am sending commands using [gcdAsyncSocket writeData:data withTimeout:-1 tag:uniqueTag]; asynchronously with unique tag.
But when gcdAsync's delegate method "socketDidReadDatawithTag" is called, it returns the data but it is not proper.e.g. If I have sent one command "010C\r" (Read RPM), and "010D\r" (Speed),with Tag 263 and 264 respectively ,and if I parse the response with tag 264 in socketDidReadDatawithTag , sometimes it returns me the data of RPM. (My response gets Mixed up or OBD Device is unable to handle asynchronous response)
NSLog(#"Command Sent for Async : %#",commandString);
NSData *data = [commandString dataUsingEncoding:NSASCIIStringEncoding];
long obdObjectTag = [obdObject getPIDTag];//Unique Tag
[gcdAsyncSocket writeData:data withTimeout:-1 tag:obdObjectTag];
NSData *readData = [#">" dataUsingEncoding:NSASCIIStringEncoding];
[gcdAsyncSocket readDataToData:readData withTimeout:-1 tag:obdObjectTag];
And in socketdidReadDatawithTag data and tag are mismatched.
The OBD-II connector (I assume it's an ELM-327) cannot really handle asynchronous calls as far as I know.
It cannot handle multiple requests at once. You send 1 command, and the OBD-II device will gather that info from the OBD-bus and return with an answer. Then it will process your next command. Ofcourse, the commands you send end up in a buffer, that will be processed one by one.
I'm thinking this might be a problem for you to make it, but I'm not sure.
I'm not familiar at all with the ios programming and what happens with those tags. You set those tags to identify what paramters are the data for?
In the reply data, you can also see for what parameter it is meant, so in the answer itself you can see that data represents RPM or Speed etc.
I hope the OBD-II part has shed some light on it. Will check this question more for some discussion perhaps.

NSurlSession - downloading many files

I have a requirement to download a number of files (around 500). I have an array containing all the urls of these files, I wanted to use NSURLSession so that i can support background downloading too.
I cant think of correct way to achieve this. If i am initiating next file download after one is completed then background downloading will not work.
shall I creating multiple downloading tasks and initiate?
Please suggest me how to achieve this.
Edit:
First, sorry for late response and here is a solution for your problem. Begin with downloading Apple's Simple Background Transfer sample. Then you will see the URLSessionDidFinishEventsForBackgroundURLSession method in view controller. You can modify this method for calling another download task like below sample and I think this is what you want to do.
There is also a comment over this method like this the session delegate will receive this message to indicate that all messages previously enqueued for this session have been delivered. So creating a queue for your requests could be better solution then this.
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
APLAppDelegate *appDelegate = (APLAppDelegate *)[[UIApplication sharedApplication] delegate];
if (appDelegate.backgroundSessionCompletionHandler) {
void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;
appDelegate.backgroundSessionCompletionHandler = nil;
completionHandler();
[self start:nil];
}
NSLog(#"All tasks are finished");
}
I was having problems with this. My app had to update itself and download news videos in the background using BACKGROUND FETCH to get json list of files then firing off n number of webservice calls to download these files using BACKGROUND TRANSFER
[NSURLSessionConfiguration backgroundSessionConfiguration:
For each file I was creating one NSSession and one NSURLSessionDownloadTask.
file 1 - NSSession1 > NSURLSessionDownloadTask1
file 2 - NSSession2 > NSURLSessionDownloadTask2
file 3 - NSSession3 > NSURLSessionDownloadTask3
This woke fine when the app was in the foreground.
But I had problems when the app was in background and woken by BACKGROUND FETCH
One file would download and then it would halt.
It was like only the first NSSession1 was executed.
It may have been that iOS was waiting till device was idle again to run next session but this was too slow
I got it working by having one NSSession and attaching all NSURLSessionDownloadTask3
NSURLSession * backgroundSession_ =
for(url to call){
create NSURLSessionDownloadTask1 (set its session:backgroundSession_)
create NSURLSessionDownloadTask2 (set its session:backgroundSession_)
create NSURLSessionDownloadTask3 (set its session:backgroundSession_)
}
Be careful when doing this
call NSSession finishTasksAndInvalidate not invalidateAndCancel
//[session invalidateAndCancel];
[session finishTasksAndInvalidate];
invalidateAndCancel will stop the session and not finish the other download tasks

Handling network exceptions IOS

I am new to objective-c, I am doing the same app for android and iPhone.
When in Java I use a try-catch block to catch a network exception and handle it.
In Objective-C I am using:
[[NSXMLParser alloc] initWithContentsOfURL:url]
So, How can I handle a network exception when parsing that input stream, so if network goes down or there's any problem I can notify user and keep my app working?.
If you are using NSXMLParser then use its delgate method..
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSLog(#"Error = %#", parseError);
}
It is never a good idea to use the initWithContentsOfURL: methods.
You are better of retrieving the the data via NSURLConnection or some library like AFNetworking. This will allow you to handle the HTTP status code and network error.
For example the NSURLConnectionDelegate has a call back method – connection:didFailWithError: which will be called in case of an error.
You can then examen the error object to see what went wrong.
Before you call the URL You can check the internet connectivity.
I suggest you to look the below link
How to check for an active Internet connection on iOS or OSX?
And I suggest for parsing XML file use raptureXML Which is very simple.
https://github.com/ZaBlanc/RaptureXML

GCDAsyncSocket for iOS is not writing out the buffer

Basically I write an NSData object:
[asyncSocket writeData:JSONRequestData withTimeout:-1 tag:1];
Which when run, invokes the delegate
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
But for some reason, when the write goes to the buffer... it's not written out to the server.
When I stop my build, I guess the socket decides to write everything and the server ends up seeing it.
How would I fix this? There's no way to flush a CocoaAsyncSocket since it's not necessary...
I've tried adding line endings, like "/n" and all, but that doesn't do anything either.
This is based on user523234's suggestion.
Basically the NSData that you're writing out needs to have some kind of signal to tell the socket that no more data will be coming in.
I appended
[GCDAsyncSocket CRLFData];
to the NSData object
Note: to use the
appendData:
Method, you must convert NSData to NSMutableData.

Executing RestKit as an NSOperartion

I am currently migrating a project that used ASIHTTPRequest and SBJson to RestKit.
The previous implementation was using an NSOperation to make the HTTP Request, parse the JSON object and make the necessary calls to the Core Data API.
I have re-factored this as follows:
#implementation UpdateBeers
#pragma mark - NSOperation
- (void)main {
[[RKClient sharedClient] get:#"/beers" delegate:self];
}
- (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response {
debug(#"didLoadResponse");
}
- (void)request:(RKRequest *)request didFailLoadWithError:(NSError *)error {
debug(#"%#", error);
}
#pragma mark - Memory
- (void) dealloc {
[super dealloc];
}
#end
The following appears in the log
sending GET request to URL http://localhost:9091/api/test. HTTP Body:
The problem is the server never receives the request.
Adding the following line :
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.3]];
to the end of the main method solves this problem.
My question is :
Should I be executing ResKit API calls as an NSOperation and if not what are my alternatives for making calls in the background?
Thanks in advance.
Perhaps I'm not fully understanding the overall problem here ... Just about everything RestKit does with respect to loading resources from the network is already in the background. Almost everything is already asynchronous, and thus running the existing asynchronous RestKit methods inside an NSOperation is duplicative and counter productive. That being said, once RestKit tells you that it's finished downloading your data (didLoadResponse), you may want to do any subsequent post-processing in an NSOperation if that part is computationally intensive and unrelated to the UI. Otherwise, don't try to outthink RestKit, just run it as in the examples and you're good to go with asynchronous goodness.
Moreover, you may want to look at using RestKit's request queues if you plan to fire off several requests at the same time. It'll still download everything asynchronously, but it'll only run as many requests at a time as you tell it ... when my app is updating, send of about seven requests at once, but the queue will run them serially instead of parallel, thus preventing any network bandwidth issues

Resources