UPDATE: Here's all the file's I'm using in my github repo. Perhaps it will help more than my code snippets:
appDelegate
mainViewController
calendarHandler
NSString* result = [NSString stringWithContentsOfURL:urlRequest encoding:NSUTF8StringEncoding error:&err];
That's the line I'm using in my project to get data from a website. I run this in an NSOperationQueue and when I run with my app in the foreground, it works without issue. However I also have my app set to run in the background using performFetchWithCompletionHandler. All of my setup code works fine using the performFetch, but when it hits the line I've outlined above, the app just hangs until I bring my app into the foreground again.
How can I let this work in the background?
In my AppDelegate I have performFetchWithCompletionHandler:
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
UINavigationController *navigationController = (UINavigationController*) self.window.rootViewController;
id topViewController = navigationController.topViewController;
if ([topViewController isKindOfClass:[ViewController class]])
{
[(ViewController*)topViewController autoLogin];
}
completionHandler(UIBackgroundFetchResultNewData);
}
My NSOperationQueue is built like this in my MainViewController:
- (void) autologin
{
NSOperationQueue* backgroundQueue = [NSOperationQueue new];
ch = [[myEventHandler alloc] init];
NSInvocationOperation* operation = [[NSInvocationOperation alloc] initWithTarget:ch selector:#selector(runEvents:) object:login];
[backgroundQueue addOperation:operation];
}
And in MyEventHandler I have runEvents
- (void) runEvents
{
NSURL* urlRequest = [NSURL URLWithString:#"http://www.google.com"];
NSError* err = nil;
NSString* result = [NSString stringWithContentsOfURL:urlRequest encoding:NSUTF8StringEncoding error:&err];
}
Try with This code:
NSString *urlString=[NSString stringWithFormat:#"%#listcontact.php?uid=%#&page=0",LocalPath,appdel.strid];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSError *error1;
NSDictionary *res=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error1];
}];
have you tried using NSURLConnection (asynchronous) instead of stringWithContentsOfURL (synchronous)?
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com"]];
[NSURLConnection sendAsynchronousRequest:request queue: [NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSString *theResult = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// blah blah
}];
Related
I'm trying to get data and show in tableView. As I have to send Request in viewDidLoad. But it took much time while loading my data, so I need it to be done in async way.
Any Suggestions or Recommendations.?
- (void)viewDidLoad {
//------castApi----//
[super viewDidLoad];
[[self tableView2]setDelegate:self ];
[[self tableView2]setDataSource:self];
array=[[NSMutableArray alloc]init];
NSString *castString = [NSString stringWithFormat:#"https://api.themoviedb.org/3/movie/%#/credits?api_key=c4bd81709e87b12e609433c49",movieIDinString];
NSURL *url=[NSURL URLWithString:castString];
NSURLRequest *request=[NSURLRequest requestWithURL:url];
connection=[NSURLConnection connectionWithRequest:request delegate:self];
if (connection){
webData= [[NSMutableData alloc]init];
}
}
Try this
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://api.themoviedb.org/3/movie/%#/credits?api_key=c4bd81709e87b12e609433c49",movieIDinString]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
}];
I'm trying to capture crash log using PLCrashReporter and send it via webservice on next App launch.
Code :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//[self checkChrash];
PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
BOOL value = [crashReporter hasPendingCrashReport];
if (value)
[self handleCrashReport];
BOOL val= [crashReporter enableCrashReporterAndReturnError:nil];
return YES;
}
#pragma mark - Crash Reports
- (void)handleCrashReport
{
PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
NSData *crashData;
NSError *error;
crashData = [crashReporter loadPendingCrashReportDataAndReturnError:&error];
PLCrashReport *report = [[PLCrashReport alloc] initWithData:crashData error:nil];
if (!crashData || !report) {
[crashReporter purgePendingCrashReport];
} else {
NSString *stringRepresentation = [PLCrashReportTextFormatter stringValueForCrashReport:report withTextFormat:PLCrashReportTextFormatiOS];
[self sendDataOnLatestCrashToServer:stringRepresentation];
[crashReporter purgePendingCrashReport];
}
}
- (void)sendDataOnLatestCrashToServer:(NSString *)crashString
{
/* NSDictionary *params = #{
#"StackTrace" : crashString
// Add more parameters as you want
};
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil];
NSURL *url = [NSURL URLWithString:#"http://www.YOURRESTSERVER.com"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0f];
[request setHTTPMethod:#"POST"];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:jsonData];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
}];
*/
}
I'm always getting return of hasPendingCrashReport as NO. I made the App crash using following :
assert(0);
NSArray * arr = [[NSArray alloc] init];
[arr objectAtIndex:10];
Please help me with this, thanks in advance
I am creating an asynchronous NSURLconnection in a popup view in ios.
To implement the asynchronous NSURLconnection I implement the methods of the NSURLDelegate.
The problem occurs when the user taps outside the popup view and the view is dismissed.
leaving the nsurlconnection callbacks and other actions inside the view incomplete.
How can I assure that the actions inside the popup complete inspite of the dismissal of the view?
I tried putting an activity indicator inside the popup view till the actions are completed, but even then a tap outside the popup view dismisses the view.
I dont want the user to be left with an inactive app till actions are completed, instead I want the actions to be completed in the background.
If you want to send an asynchronous connection you can use this methods.
GET REQUEST
-(void)placeGetRequest:(NSString *)action withHandler:(void (^)(NSURLResponse *response, NSData *data, NSError *error))ourBlock {
NSString *url = [NSString stringWithFormat:#"%#/%#", URL_API, action];
NSURL *urlUsers = [NSURL URLWithString:url];
NSURLRequest *request = [NSURLRequest requestWithURL:urlUsers];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:ourBlock];
}
POST REQUEST
-(void)placePostRequest:(NSString *)action withData:(NSDictionary *)dataToSend withHandler:(void (^)(NSURLResponse *response, NSData *data, NSError *error))ourBlock {
NSString *urlString = [NSString stringWithFormat:#"%#/%#", URL_API, action];
NSLog(urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// Creamos el JSON desde el data
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dataToSend options:0 error:&error];
NSString *jsonString;
if (! jsonData) {
NSLog(#"Got an error: %#", error);
} else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSData *requestData = [NSData dataWithBytes:[jsonString UTF8String] length:[jsonString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: requestData];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:ourBlock];
}
}
EXAMPLE OF USE
- (void) getMyMethod:(NSString *)myParam1
myParam2:(NSString *)myParam2
myParam3:(NSString *)myParam3
calledBy:(id)calledBy
withSuccess:(SEL)successCallback
andFailure:(SEL)failureCallback{
[self placeGetRequest:[NSString stringWithFormat:#"api/myMethod?myParam1=%#&myParam2=%#&myParam3=%#",myParam1, myParam2, myParam3]
withHandler:^(NSURLResponse *response, NSData *rawData, NSError *error) {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSInteger code = [httpResponse statusCode];
NSLog(#"%ld", (long)code);
if (code == 0){
// error
} else if (!(code >= 200 && code < 300) && !(code == 500)) {
NSString *string = [[NSString alloc] initWithData:rawData
encoding:NSUTF8StringEncoding];
NSLog(#"ERROR (%ld): %#", (long)code, string);
[calledBy performSelector:failureCallback withObject:string];
} else {
// If you receive a JSON
NSMutableDictionary *result = [NSJSONSerialization JSONObjectWithData:rawData options:0 error:nil];
// If you receive an Array
// NSArray *result = [NSJSONSerialization JSONObjectWithData:rawData options:0 error:nil];
// If you receive a string
// NSString *result = [[NSString alloc] initWithData:rawData encoding:NSUTF8StringEncoding];
[calledBy performSelector:successCallback withObject:result];
}
}];
}
CALL YOU MUST DO IN YOUR VIEW/CONTROLLER/ETC
(...)
[api getMyMethod:myParam1Value myParam2:myParam2Value myParam3:myParam3Value calledBy:self withSuccess:#selector(getMyMethodDidEnd:) andFailure:#selector(getMyMethodFailureFailure:)];
(...)
// Don't forget to set your callbacks functions or callbacks will do your app crash
-(void)getMyMethodDidEnd:(id)result{
// your actions with the result
// ...
}
-(void)getMyMethodFailure:(id)result{
// your actions with the result
// ...
}
To prevent the dismissal of popup view when tapping out side u need to implement this delegate method
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
return NO;
}
dismiss it by using the action
- (void)someAction
{
//check the operations are completed
.....
.....
[popoverController dismissPopoverAnimated:YES];
}
i want to use async req to get json data, i am doing this by syncrouns already, but now requirement is change, but i am unable to modify this code to aync, beacuse i have to return NSdata
+ (NSString *)stringWithUrl:(NSURL *)url
{
// if(kShowLog)
NSLog(#"%#", url);
NSURL *newURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#",url]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:newURL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:1];
// Fetch the JSON response
NSData *urlData;
NSURLResponse *response;
NSError *error;
// NSOperationQueue *opQueue;
// Make synchronous request
urlData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
return [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
}
call stringWithUrl on a 2. thread if you want to keep returning the data. (I'd go with async data
dispatch_async(dispatch_get_global_queue(), ^{
NSData *d = [self stringWithUrl:myURL];
...
//update ui
dispatch_sync(dispatch_get_main_queue(), ^{
...
});
});
a way that would work but is QUITE the hack (which apple employed in older APIs on the mac all the time) would be to run the runloop while waiting:
hackisch :: but wraps async in sync given the completion block runs on the same thread then the runloop
__block NSString *responseString = nil;
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:myurl]
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
responseString = [[NSString alloc] initWithData:Data encoding:NSUTF8StringEncoding];
if(!responseString) {
responseString = #"";
}
}];
while(!responseString) {
[NSRunloop currentRunloop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1];
}
return responseString;
You have to create a separate thread for this process, Synchronous call of getting json data will block your main thread.
I'm changing your code to do asynchronous operation for getting json data from web service.
+ (void)stringWithUrl:(NSURL *)url
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
// if(kShowLog)
NSLog(#"%#", url);
NSURL *newURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#",url]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:newURL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:1];
// Fetch the JSON response
NSData *urlData;
NSURLResponse *response;
NSError *error;
// NSOperationQueue *opQueue;
// Make synchronous request
urlData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
dispatch_sync(dispatch_get_main_queue(), ^{
//Here you have to put your code, which you wanted to get executed after your data successfully retrived.
//This block will get executed after your request data load to urlData.
});
});
}
What's wrong with the Asynchronous then,
NSString *responseString;
NSOperationQueue *operation = [[NSOperationQueue alloc]init];
[NSURLConnection sendAsynchronousRequest:request queue:operation completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(#"data %#", data);
responseString = [[NSString alloc] initWithData:Data encoding:NSUTF8StringEncoding];
}];
return responseString;
I'm just doing exactly what I do for HTTP requests:
NSString *urlStrig = [NSString stringWithFormat:#"https://mysite.com/search.json?param1=10¶m2=String¶m3=20"];
NSURL *url = [NSURL URLWithString:urlStrig];
NSOperationQueue *queue = [NSOperationQueue new];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:Timeout];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSLog(#"URL:%#\nResponse: %#\nStatusCode: %i\nError: %#", url, [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding], ((NSHTTPURLResponse *)response).statusCode, error);
}];
But all I got is a 403 status code everytime. Testing it via curl in the terminal works fine.
Is there any problem between HTTPS and NSURLConnection?