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];
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 i am working on fixing the deprecation issues present in the application. I am using XCode 11.3 in Mojave MacOS 10.14 and Our application contains the following line of code
[NSURLConnection sendSynchronousRequest:request returningResonse:response error:Error]
A warning message getting displayed as sendSynchronousRequest is deprecated and it is suggesting to use [NSURLSession dataTaskWithRequest:completionHandler:] .
so i have implemented the following code
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURL * url = [NSURL URLWithString:#"MyURLHere"];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response:%# %#\n", response, error);
if(error == nil)
{
NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
}
}];
[dataTask resume];
i found that data is being returned as nil always. When i debugged the code, i found that even [NSURLSessionConfiguration defaultSessionConfiguration] is being returned as nil. Can you please suggest what needs to be done in order to fix these issues?
This works perfectly on iPhone (Simlulator and Device) but on Watch OS2 i get blank data. What might be the issue with this ?
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:theRequest
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error)
{
theData = [[NSString alloc]initWithBytes:[data bytes] length:[data length] encoding:NSUTF8StringEncoding];
NSLog(#"%#", theData);
}];
[task resume];
Sorry found the mistake. Had to add Allows Arbitrary Loads on the WatchKit extension. After adding i got the result.
[self.table setNumberOfRows:[arrurlimg1 count ]withRowType:#"QuoteTableRow"];
for (NSInteger i = 0; i < self.table.numberOfRows; i++) {
ICBQuoteTableRow* theRow = [self.table rowControllerAtIndex:i];
NSURLSessionConfiguration *config =[NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session =[NSURLSession sessionWithConfiguration:config];
NSURLSessionTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data1, NSURLResponse * _Nullable response, NSError * _Nullable error)
{
for (int i=0; i<arrurlimg1.count; i++)
{
UIImage *image =imgData1;
[theRow.myFirstImage setImage:image];
// [theRow.myGroup setBackgroundImage:image];
}
}];
[task resume];
}
My Code works just fine. What I need help, or clarification on is Nested NSURLSessionDataTask instances.
I'm making two asynchronously calls, the second call is dependent on the first.
So I make the first NSURLSessionDataTask (firstUrlCall) call which returns an array of objects. For each object in my array I then call the second NSURLSessionDataTask (secondUrlCall) and pass in a dataID.
As I mentioned before, it works. I just see alot of lines repeated and REPEATED CODE IS NOT SEXY!!!
So is there anything I can do to prevent this catastrophe? I need my code to be SEXY!
#property (nonatomic, strong) NSURLSession *Session;
FIRST CALL
-(void) firstUrlCall {
NSString *urlString = #"https://api.FIRSTURLCALL.com";
NSURLSessionDataTask *dataTask = [session
dataTaskWithURL:[NSURL URLWithString:urlString]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (!error) {
NSDictionary *returnData = [NSJSONSerialization JSONObjectWithData:data
options:0
error:nil];
[returnData enumerateKeysAndObjectsUsingBlock:^(id dataID, id obj, BOOL *stop) {
/*
-->here is where I call secondUrlCall<--
*/
[self secondUrlCall:dataID];
}];
}
});
}];
[dataTask resume];
}
SECOND CALL
-(void) secondUrlCall:(NSString *)dataID {
NSString *urlString = [NSString stringWithFormat:#"https://api.SECONDURLCALL.com?dataID=%#",dataID];
NSURLSessionDataTask *dataTask = [session
dataTaskWithURL:[NSURL URLWithString:urlString]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (!error) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data
options:0
error:nil];
if ([[json objectForKey:#"type"] isEqualToString:#"sexy"]) {
[tableArray addObject:json];
// Reload table data
[self.tableView reloadData];
}
}
});
}];
[dataTask resume];
}
PS: Sorry if you were offended from my extensive use of the word SEXY :)
Oh my goodness! What if the network is intermittent or goes down half way through?
I would take the results of the first call and put each one into an operation queue, then when processing each operation if it fails you can re-queue it.
Here i get data from a url.
I declare my NSString in the header file of my view controller
#property NSString *contentsOfUrl;
then i get the contents of a url and assign it to this string
-(void)press
{
NSURLSession *session1 = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session1 dataTaskWithURL:[NSURL URLWithString:#"http://api.lmiforall.org.uk/api/v1/soc/code/2222"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (((NSHTTPURLResponse*) response).statusCode == 200) {
if (data) {
contentsOfUrl = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
}
}] resume];
NSLog(#"%#", contentsOfUrl);
}
For some reason my variable is null. However when i put the NSLog in the if statement it has the correct data.
This is because contentsOfUrl is assigned inside the completion handler that is called asynchronous.
So your block:
^(NSData *data, NSURLResponse *response, NSError *error) {
if (((NSHTTPURLResponse*) response).statusCode == 200) {
if (data) {
contentsOfUrl = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
}
}
is getting called after the NSLog line.
If you want to do something with this data do it right from inside the block