Having an app written in Objective-C targeting iOS8/9 there are real vantange in performance or stability updating code using NSURLSession
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithRequest:request
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
dispatch_sync(dispatch_get_main_queue(), ^{
//UPDATE UI
});
}] resume];
in place of code like the following that use NSURLConnection:
[NSURLConnection sendAsynchronousRequest:request
queue:[CMRequestManager connectionQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
dispatch_sync(dispatch_get_main_queue(), ^{
//UPDATE UI
});
}];
If you decide to run the code in a WatchKit extension or on tvOS at some point in the future, then yes. Otherwise, if the snippet above is representative of the way you're using the API, then I probably wouldn't bother rewriting it. With that said, this is very much a matter of opinion.
Related
I recently upgraded to MacOS Ventura and discovered that software I'd written in the past to scrape data from a webpage would no longer work. That code used initWithContentsOfURL to access and download a sequence of pages which my code would then process (yes, I know synchronous networking is bad practice, but this is a research app only I use, not commercial software).
I then modified to code to use NSURLSessionTask and dataTaskWithURL to grab the pages asynchronously, which worked great, except... since my software is now making 10 requests in rapid order, the website is generating Error 1015 informing me that I'm being rate limited and temporarily banned.
I guess this means I now have to slow down my code when making the requests? My code looks like this (cutting it down from 10 requests to 3, removing error handling, and NSURL initialization):
NSURLSession *session = [NSURLSession sharedSession];
__block NSURLSessionTask *task1 = nil;
__block NSURLSessionTask *task2 = nil;
__block NSURLSessionTask *task3 = nil;
task1 = [session dataTaskWithURL:pageURL1 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (data) {
task1Source = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
[task2 resume];
}];
task2 = [session dataTaskWithURL:pageURL2 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (data) {
task2Source = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
[task3 resume];
}];
task3 = [session dataTaskWithURL:pageURL3 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (data) {
task3Source = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
}];
[task1 resume];
The site I'm hitting obviously does not like this, which has generated the rate limit error. Is there a preferred way to distribute the requests or otherwise generate an acceptable delay that will be acceptable to the site (I also have a request out to the site's tech support)?
Thanks!
I am new to Mac application development and our existing Mac application contains the following line of code
[NSURLConnection sendSynchronousRequest:request returningResonse:response error:Error
A warning message getting displayed as
sendSynchronousRequest is deprecated in macOS 10.11
and suggesting to use [NSURLSession dataTaskWithRequest:completionHandler:]
I have implemented the following code changes to use NSURLSession as suggested but it is returning the value of data as "nil". Can you please suggest what needs to be done in order to get the required data in response?
__block NSError *WSerror;
__block NSURLResponse *WSresponse;
__block NSData *myData;
NSURLSession *session =[NSURLSession sharedSession];
[[session completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
myData = data;
WSresponse =response;
WSerror = error;
}] resume];
NSString *theXml = [[NSString alloc] initWithData:myData encoding:NSUTF8StringEncoding];
return theXml;
The completion handler is asynchronous. You have to do your work inside the completion handler.
The __block declarations are pointless.
NSURLSession *session =[NSURLSession sharedSession];
[[session completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"%#", error);
} else {
NSString *theXml = [[NSString alloc] initWithData: data encoding:NSUTF8StringEncoding];
// do something with `theXml`
}
}] resume];
How we call sync call But the give response asynch.here is my code.
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];
We can't and we never could.
The previous approach was halting the execution of the tread, continuing after getting the data or after a timeout.
I am trying to pull some data from my local node server. The server is getting the get request and logging it, but for some reason my iOS app will not execute any of the code that I have in the completion handler. Here is the code:
- (IBAction) buttonPressed{
NSURL *url = [NSURL URLWithString:#"http://127.0.0.1:3000/"];
NSURLSessionDataTask *dataTask =
[self.session dataTaskWithURL:url
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error){
nameLabel.text = #"yay!";
/*
if (!error){
nameLabel.text = #"noerr";
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse *)response;
if (httpResp.statusCode == 200){
NSError *jsonErr;
NSDictionary *usersJSON =
[NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingAllowFragments
error:&jsonErr];
if (!jsonErr){
// nameLabel.text = usersJSON[#"username"];
nameLabel.text = #"nojerr";
}
else{
nameLabel.text = #"jsonErr";
}
}
}
else{
nameLabel.text = #"Err";
}
*/
}];
[dataTask resume];
}
When the program is run, the nameLabel is not changed to "yay". However if I try to change the nameLabel before the NSURLSessionDataTask line, it changes.
NSURLSessionDataTask runs in a background thread. To update anything in the user interface such as labels, buttons, table views, etc, you must do so on the main thread. If you want to update the label text from the completionHandler block then you need to update the label in the main thread like so:
dispatch_sync(dispatch_get_main_queue(), ^{
nameLabel.text = #"yay!";
});
try this magic:
static NSURLSession* sharedSessionMainQueue = nil;
if(!sharedSessionMainQueue){
sharedSessionMainQueue = [NSURLSession sessionWithConfiguration:nil delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
}
NSURLSessionDataTask *dataTask =
[sharedSessionMainQueue dataTaskWithURL:url completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error){
//now will be on main thread
}];
[dataTask resume];
This gives you the original behavior of NSURLConnection with the completing handler on the main thread so you are safe to update the UI. However, say you would like to parse the download or do some heavy processing, in that case you might benefit from the completion handler on the operation queue's background thread and then using dispatch_sync to the main thread as a final step.
I have a connection to server , and i want to release its queue, i don't now how.
[NSURLConnection
sendAsynchronousRequest:request
queue:[[NSOperationQueue alloc] init]
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error)
//some if else statements
}];
i dont get how to release this queue argument between 2 connections ?
If you are using ARC, you do not have to do anything.
If not, you can include autorelease.