Is it possible to push to a new view controller from ConnectionDidFinishLoading ?
I have the following and it performs the ConnectionDidFinishLoading but does not push to new view controller.
-(void)connectionWithURLString:(NSMutableArray *)urlString
{
NSDate *now = [NSDate date];
int userID = [[clientDataStruct.clientData objectForKey:#"number"] intValue];
NSDate *date = self.datePicker.date;
// NSLog(#"obj: %#", urlString);
NSString *extrString = [NSString stringWithFormat:#", customerdetails:{customer_id = %d, job_date = %#, date_created = %#}",userID,date, now];
NSString *post = [NSString stringWithFormat:#"json=quote:{%#%#}", urlString, extrString ];
NSLog(#"post: %#", post);
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:NO];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *value = [defaults objectForKey:#"value"];
NSString *jsonUrl = [NSString stringWithFormat:#"xxx?task=add_quote&user_id=%#&customer_id=%#",value, [clientDataStruct.clientData valueForKey:#"number"]];
[request setURL:[NSURL URLWithString:jsonUrl]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:postData];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
if (!connection)
NSLog(#"Connection failed!");
}
- (void)Success
{
UIStoryboard *subVc = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
UserTableView *userTable = [subVc instantiateViewControllerWithIdentifier:#"UserTableView"];
userTable.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self.navigationController pushViewController:userTable animated:YES];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"%#", error);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self performSelectorOnMainThread:#selector(Success) withObject:Nil waitUntilDone:YES];
NSLog(#"connectionDidFinishLoading%#", connection);
}
Everything works, and returns my data and data gets added into the SQL. My NSLog shows that ConnectionDidFinishLoading. But it does not push to the new View Controller.
Thanks for the help, being scratching my head on this one.
Thanks to Fahim advise allowed me to debug further, The Navigation view broke with a returned model controller. Changed it to push and all is working
Point 1
This is not working with you because you don't have navigation controller. Make sure that you have navigation controller.
Point 2
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self performSelectorOnMainThread:#selector(LoginSuccess) withObject:Nil waitUntilDone:YES];
NSLog(#"connectionDidFinishLoading%#", connection);
}
This is something wrong. Even if user have entered incorrect username or password, you are still allowing user to get logged in.
Check the response that you are getting in connectionDidFinishLoading and then based on this response do the transition.
e.g. if you have PHP at backend your code will be
sql query here to add data
if (data added) {
echo "valid";
} else {
echo "invalid";
}
now check this response in connectionDidFinishLoading and based on this do the transition
First check that if your LoginSuccess is getting called if yes then paste this
UserTableView * userTable =[self.storyboard instantiateViewControllerWithIdentifier:#"UserTableView"];
[self.navigationController pushViewController:userTable animated:YES]
like this but replace ResultsTableView with UserTableView
Related
I am having action for login button in view controller but i have to use some condition in appdelegate.m that if user logged in already then viewcontroller login action method will fire and if not logged in then only login page will open?
Please help me
in AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([[NSUserDefaults standardUserDefaults]boolForKey:#"IsFirstTime"])
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
HomePageVC *lvc = [storyboard instantiateViewControllerWithIdentifier:#"HomePageVC"];
[(UINavigationController *)self.window.rootViewController pushViewController:lvc animated:NO];
}
else
{
[[NSUserDefaults standardUserDefaults]setBool:YES forKey:#"IsFirstTime"];
[[NSUserDefaults standardUserDefaults]synchronize];
}
return YES;
}
in viewcontroller.m
- (IBAction)Login:(id)sender
{
[self.indicator startAnimating];//The ActivityIndicator Starts Animating Here
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:BaseUrl#"login"]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"*/*" forHTTPHeaderField:#"Accept"];
[request setHTTPMethod:#"POST"];
NSString *mapData = [NSString stringWithFormat:#"userName=gautam.kar#eyeforweb.com&userPassword=1234567&api_key=ZWZ3QDEyMw==&api_password=456789"];
NSData *postData = [mapData dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
[request setHTTPBody:postData];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(error == nil)
{
NSString *text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"Data = %#",text);
NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSLog(#"jsondic= %#",jsonDic);
NSDictionary *userDataDic = [jsonDic objectForKey:#"record"];
[DataModel setEmailAdd:[userDataDic objectForKey:#"emailAdd"]];
[DataModel setName:[userDataDic objectForKey:#"Name"]];
[DataModel setCity:[userDataDic objectForKey:#"city"]];
[DataModel setCountry:[userDataDic objectForKey:#"country"]];
[DataModel setRegistrationID:[userDataDic objectForKey:#"registrationID"]];
[DataModel setPhoneNo:[userDataDic objectForKey:#"phoneAdd"]];
[DataModel setState:[userDataDic objectForKey:#"state"]];
[DataModel settimeZone:[userDataDic objectForKey:#"timezone"]];
[DataModel setDisclaimer:[userDataDic objectForKey:#"disclaimer"]];
dispatch_async(dispatch_get_main_queue(), ^{
[self.indicator stopAnimating];//The ActivityIndicator Stops Animating when Response Arrives
NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"text= %#",text);
NSError *error = nil;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
[self checkUserSuccessfulLogin:json];
});
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.indicator stopAnimating];
});
NSLog(#"Error : %#",error.description);
}
}];
[postDataTask resume];
}
- (void)checkUserSuccessfulLogin:(id)json
{
// NSError *error;
NSDictionary *dictionary = (NSDictionary *)json;
if ([[dictionary allKeys] containsObject:#"login"])
{
if ([[dictionary objectForKey:#"login"] boolValue])
{
NSString *strID = [[NSUserDefaults standardUserDefaults] stringForKey:#"textField1Text"];
NSString *strPWD = [[NSUserDefaults standardUserDefaults] stringForKey:#"textField2Text"];
[[NSUserDefaults standardUserDefaults] setValue:[dictionary objectForKey:#"user_id"] forKey:#"CurrentUserLoggedIn"];
NSString *strUser = [[NSUserDefaults standardUserDefaults] stringForKey:#"CurrentUserLoggedIn"];
[[NSUserDefaults standardUserDefaults]synchronize];
[self saveLoginFileToDocDir:dictionary];
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
HomePageVC *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"HomePageVC"];
[self.navigationController pushViewController:vc animated:YES];
}
else
{
NSLog(#"Unsuccessful, Try again.");
UIAlertView *alertLogin = [[UIAlertView alloc]initWithTitle:#"Error" message:#"Wrong Username Or Password" delegate:self cancelButtonTitle:#"cancel" otherButtonTitles:nil];
[alertLogin show];
}
}
}
- (void)saveLoginFileToDocDir:(NSDictionary *)dictionary
{
NSArray *pListpaths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *pListdocumentsDirectory = [pListpaths objectAtIndex:0];
NSString *path = [pListdocumentsDirectory stringByAppendingPathComponent:#"Login.plist"];
BOOL flag = [dictionary writeToFile:path atomically:true];
if (flag)
{
NSLog(#"Saved");
}
else
{
NSLog(#"Not Saved");
}
}
- (NSDictionary *)getLoginFileFromDocDir
{
NSArray*pListpaths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString*pListdocumentsDirectory = [pListpaths objectAtIndex:0];
NSString *path = [pListdocumentsDirectory stringByAppendingPathComponent:#"Login.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
return dict;
}
What you need is not to check your controller in AppDelegate.m, even though that is what you're asking.
Your real problem is " how can I access data from two different places ? ".
Right now, you're telling AppDelegate he "knows" your view controllers. It shouldn't.
What you need is one (actually a lot more but you'll learn that with time) new class, that handles the Login calls and state, and all that is login related.
Call that class the... LoginManager.
In that class, you could have some methods, like Login() or Logout(), or anything you would like.
Now you have an external source of data, your login manager knows everything he musts knows about the login. You should even add some properties, like a boolean IsLoggedIn or anything you might need.
And that source of data is what AppDelegate needs to know. Not the controllers. With that kind of architecture, EVERYONE that needs the login information can access it from that class (which could / should be a singleton class, look it up on the internet, its very easy.
In your viewcontroller, you can simply do Loginmanager.login, and in appdelegate, you can check .isloggedin.
That helps you a lot, because you don't have to instantiate view controllers in appdelegate, which is really a lot of work. You're splitting the work and the tasks between classes, which is what a good programmer does. Remember, your class should have only one job, not more, not less. Your VC handles the user inteface, not the webservic calls, not the login, nothing. If it does, it means you need to create another class :)
Once you've implemented all that (read my answer as many times as necessary to make sure you understand), you'll have no problem accessing that kind of data in other place of your app.
Note that you shouldn't abuse singleton classes or static classes (especially static), but again, you'll probably make many mistakes and learn from them, like we all did when we started.
Create your ViewController Object like below,
viewcontroller *objYourVC=[[viewcontroller alloc]init];
Now call method from Appdelegate like below:
[objYourVC functionToBeCalled:nil];
OR
[objYourVC functionToBeCalled:self];
Example,
if(AlreadyLogin){
//call viewcontroller method
viewcontroller *objYourVC=[[viewcontroller alloc]init];
[objYourVC functionToBeCalled:nil];
}
At first i just send data to server using GET method, I receive a response like below
2015-11-16 14:21:42.168 smartschool[1963:348015] Item actcode: ZQRTNN68
2015-11-16 14:21:42.169 smartschool[1963:348015] Item parentid: 8
How can i display the activation code to a label of the next viewController.
Here is my code:
#import "RegistrationViewController.h"
#interface RegistrationViewController ()
#end
#implementation RegistrationViewController
{
NSMutableData *mutableData;
#define URL #"http://192.168.1.166/bustracking/activation/requestActivationCode"
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(IBAction)sendDataUsingGet:(id)sender{
[self sendDataToServer : #"GET"];
}
-(void) sendDataToServer : (NSString *) method
{
NSString *parentName = parent_name.text;
NSString *contactNumber = contact_number.text;
NSString *beaconid = #"145801000095";
//NSString *beaconMacAdd = #"14:58:01:00:00:95";
if(parentName.length > 0 && contactNumber.length > 0){
NSLog (#"Getting response from server...");
NSMutableURLRequest *request = nil;
// Only Difference between POST and GET is only in the way they send parameters
if([method isEqualToString:#"GET"]){
NSString *getURL = [NSString stringWithFormat:#"%#?parent_name=%#&contact_number=%#&beacon_id=%#", URL, parentName, contactNumber, beaconid];
//url = [NSURL URLWithString: getURL];
getURL = [getURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString: getURL];
request = [NSMutableURLRequest requestWithURL:url];
NSLog(#"urlinfo: %#", url);
NSLog(#"link: %#", getURL);
}
[request setHTTPMethod:method];
[request addValue: #"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"connection: %#", connection);
if( connection )
{
mutableData = [NSMutableData new];
}
else
{
NSLog (#"NO_CONNECTION");
return;
}
}
else
{
NSLog(#"NO_VALUES");
}
}
#pragma mark NSURLConnection delegates
-(void) connection:(NSURLConnection *) connection didReceiveResponse:(NSURLResponse *)response
{
[mutableData setLength:0];
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[mutableData appendData:data];
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog (#"NO_CONNECTION");
return;
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError *error = nil;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:mutableData options:kNilOptions error:&error];
NSArray *fetchedArr = [json objectForKey:#"response"];
NSString *responseActCode;
for (NSDictionary *user in fetchedArr)
{
responseActCode = [user objectForKey:#"activation_code"];
NSLog(#"Item actcode: %#", responseActCode);
NSLog(#"Item parentid: %#", [user objectForKey:#"parent_id"]);
//NSLog(#"Item actcode: %#", [user objectForKey:#"activation_code"]);
}
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:responseActCode forKey:#"HighScore"];
[defaults synchronize];
NSLog(#"from data: %#", [defaults objectForKey:#"HighScore"]);
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Activation Code"
message:(#"%#", responseActCode)
delegate:nil //or self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
#end
If the returning data is in dictionary format, declare nsdictionary in header.h class on which you wan to transfer data, similarly you can use array and string, now if you are using a storyboard, below is the method.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
vc.dictionary = self.dictionary.
}
}
and you want to transfer data upon cell tap this is what you have to do.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"YOUR_SEGUE_NAME_HERE"" sender:self];
}
When "performSegueWithIdentifier" is called, this method automatically redirected to "prepareForSegue" method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath= [self.tableView indexPathForSelectedRow];
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
now this time its array.
vc.array= [array[indexpath.row] valueforkey#"jsonkey"];
}
}
There are many ways to pass data between view controllers. Here's one example:
Create a public property in "SomeViewController" class(eg: responseActCodeString) and set that property to your activation code(eg: responseActCode).
SomeViewController *someViewController = [[SomeViewController alloc] initWithNib:#"SomeViewController " bundle:nil];
someViewController.responseActCodeString = responseActCode;
[self pushViewController:someViewController animated:YES];
You can also use notifications, user defaults as an alternatives.
Also look at this link.
For storyboards add following method in initial view controller:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"someIdentifier"]){
SomeViewController*someViewController= (SomeViewController*)segue.destinationViewController;
someViewController.responseActCodeString = responseActCode;
}
}
My app is asking for permission to “Have offline access”, why? It's the weirdest thing. I've done a bit of searching and haven't really found anything that's worked. I've tried using these for scopes:
https://www.googleapis.com/auth/plus.profile.emails.read
https://www.googleapis.com/auth/plus.login
and that didn't seem to help.
Below is a screenshot and some of my code to help you see what's going on:
Some of my code:
#import "ViewController.h"
NSString *callbakc = #"http://localhost/";
NSString *client_id = #“CLIENT ID“;
NSString *scope = #"https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile+https://www.google.com/reader/api/0/subscription";
NSString *secret = #“SECRET”;
NSString *visibleactions = #"http://schemas.google.com/AddActivity";
#interface ViewController () {
NSString *authAccessToken;
UIAlertController *alertController;
}
#property (strong, nonatomic) NSMutableData *receivedData;
#property (weak, nonatomic) IBOutlet UIWebView *webView;
#end
#implementation ViewController
#pragma mark - Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
NSString *url = [NSString stringWithFormat:#"https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=%#&redirect_uri=%#&scope=%#&data-requestvisibleactions=%#",client_id,callbakc,scope,visibleactions];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:10];
[_webView loadRequest:request];
}
#pragma mark - WebView Delegate
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
[self performSelector:#selector(progressDelay:) withObject:nil afterDelay:0.0];
if ([[[request URL] host] isEqualToString:#"localhost"]) {
// Extract oauth_verifier from URL query
NSString* verifier = nil;
NSArray* urlParams = [[[request URL] query] componentsSeparatedByString:#"&"];
for (NSString* param in urlParams) {
if (![param isEqualToString:#"error=access_denied"]) {
NSArray* keyValue = [param componentsSeparatedByString:#"="];
NSString* key = [keyValue objectAtIndex:0];
if ([key isEqualToString:#"code"]) {
verifier = [keyValue objectAtIndex:1];
// NSLog(#"verifier %#",verifier);
break;
}
}
else {
[self.navigationController popViewControllerAnimated:NO];
}
}
if (!verifier==0) {
[self showAlertViewWithTitle:#"" message:#"Please wait" okAction:NO];
NSString *data = [NSString stringWithFormat:#"code=%#&client_id=%#&client_secret=%#&redirect_uri=%#&grant_type=authorization_code", verifier,client_id,secret,callbakc];
NSString *url = [NSString stringWithFormat:#"https://accounts.google.com/o/oauth2/token"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[data dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPShouldHandleCookies:NO];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"Connection: %#", theConnection);
self.receivedData = [[NSMutableData alloc] init];
}
else {
// cancel button click
NSLog(#"not Verified!!");
}
return NO;
}
return YES;
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
// show progress
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[alertController dismissViewControllerAnimated:YES completion:nil];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
if (error.code==102) //Frame load interrupted
return;
[alertController dismissViewControllerAnimated:YES completion:nil];
[self showAlertViewWithTitle:#"Error" message:[error localizedDescription] okAction:YES];
}
#pragma mark - NSURLConnection Delegate
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
[self showAlertViewWithTitle:#"Error" message:[NSString stringWithFormat:#"%#", error] okAction:YES];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *response = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding];
NSData *data = [response dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *tokenData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if ([tokenData objectForKey:#"access_token"]) {
authAccessToken = [tokenData objectForKey:#"access_token"];
[self getUserInfo:authAccessToken];
}
else {
[alertController dismissViewControllerAnimated:YES completion:nil];
NSLog(#"RESULT: %#", tokenData);
[self showAlertViewWithTitle:[tokenData objectForKey:#"name"] message:[NSString stringWithFormat:#"%#", tokenData] okAction:YES];
// Flush all cached data
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
}
#pragma mark - Private Method Implementation
-(void)getUserInfo:(NSString *)token {
NSString *url = [NSString stringWithFormat:#"https://www.googleapis.com/oauth2/v1/userinfo?access_token=%#",token];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"GET"];
[request setHTTPShouldHandleCookies:NO];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"Connection: %#", theConnection);
self.receivedData = [[NSMutableData alloc] init];
}
-(void)progressDelay:(id)sender {
// Dismiss progress
}
#end
Any help would be greatly appreciated!
Thank you
This is from https://stackoverflow.com/questions/32210920/why-is-my-app-asking-for-permission-to-have-offline-access?answertab=oldest#tab-top:
This is normal behavior and occurs when the user has granted
permission already.
Basically, no need to worry about it unless you really don't want that
showing up, in that case, you need to un auth the users old token
before requesting a new one.
I'm not exactly sure how because I haven't done this before, but before you authorize a new token you need to un-authorize the old one.
You'll need to modify the -(void)getUserInfo:(NSString *)token method.
For some reason unknown to me. The email scope pops up with
Have offline access
If you want to remove the have offline access remove the email scope. Personally I think it is miss leading to users that you are asking for email access yet are prompted for offline access. Technically speaking all OAuth2 that returns a refresh token gives offline access so the user should always be told that you are getting offline access but it doesnt.
I am using a button action to update the value of a MySQL table field. The update is perform in the web server, but I need to update a UILabel text in my view Controller.
This is the code I have implemented:
- (IBAction)votarAction:(id)sender {
//URL definition where php file is hosted
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.mycompany.myqueue", 0);
dispatch_async(backgroundQueue, ^{
int categoriaID = [[detalleDescription objectForKey:#"idEmpresa"] intValue];
NSString *string = [NSString stringWithFormat:#"%d", categoriaID];
NSLog(#"ID EMPRESA %#",string);
NSMutableString *ms = [[NSMutableString alloc] initWithString:#"http://mujercanariasigloxxi.appgestion.eu/app_php_files/cambiarvaloracionempresa.php?id="];
[ms appendString:string];
// URL request
NSLog(#"URL = %#",ms);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:ms]];
//URL connection to the internet
NSURLConnection *connection=[[NSURLConnection alloc]initWithRequest:request delegate:self];
dispatch_async(dispatch_get_main_queue(), ^{
//update your label
});
});
}
#pragma NSURLConnection Delegate Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//buffer is the object Of NSMutableData and it is global,so declare it in .h file
buffer = [NSMutableData data];
NSLog(#"ESTOY EN didReceiveResponse*********");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"ESTOY EN didReceiveDATA*********");
[buffer appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//Here You will get the whole data
NSLog(#"ESTOY EN didFINISHLOADING*********");
NSError *jsonParsingError = nil;
NSArray *array = [NSJSONSerialization JSONObjectWithData:buffer options:0 error:&jsonParsingError];
//And you can used this array
NSLog(#"ARRAY = %#",array);
//HERE LABEL.TEXT UPDATE CODE
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"ERROR de PARSING");
NSLog(#"ESTOY EN didFAILWITHERROR*********");
}
As I told you, the field value at the MySQL table is updated every time the button is tapped, but the problem is that the NSURLConnection delegate methods are never called.
Any help is welcome
In your view controller's header file add: <NSURLConnectionDelegate>
Also, there's no need to throw the NSURLConnection into a seperate background process, maybe that's why the delegates aren't called. NSURLConnection is already asynchronous
Perhaps try something like this:
- (IBAction)votarAction:(id)sender
{
int categoriaID = [[detalleDescription objectForKey:#"idEmpresa"] intValue];
NSString *originalString = [NSString stringWithFormat:#"%d", categoriaID];
NSMutableString *mutablesString = [[NSMutableString alloc] initWithString:#"http://mujercanariasigloxxi.appgestion.eu/app_php_files/cambiarvaloracionempresa.php?id="];
[mutableString appendString:originalString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:mutableString]];
request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
request.timeoutInterval = 5.0;
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
if (data)
{
NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dispatch_async(dispatch_get_main_queue(), ^
{
// Update your label
self.label.text = [array objectAtIndex:someIndex];
});
}
else
{
// Tell user there's no internet or data failed
}
}];
}
I have working code but I need advice/direction if there is a better approach or if problems will arise using my current approach. The MBProgressHUD starts in the viewDidLoad, I then have a JSON method that posts and receives a response. It is a synchronous task because I need the information to modify labels on the screen. At the end of the JSON method is a call to stop the MBProgressHUD.
My viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
//some code missing
//start loading
MBProgressHUD * hud = [MBProgressHUD showHUDAddedTo: self.view animated:YES] ;
hud.labelText =#"Loading Information";
hud.detailsLabelText=#"Please wait.";
hud.dimBackground = YES;
}
My viewDidAppear:
-(void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:YES];
[self getJSON];
}
My getJSON method:
-(void) JSON{
//post
NSMutableString * postString = [NSMutableString stringWithString:homeUrl];
[postString appendString:[NSString stringWithFormat:#"?%#=%#",#"email",self.email]];
[postString appendString:[NSString stringWithFormat:#"&%#=%#",#"pass",self.pass]];
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:postString]];
[request setHTTPMethod:#"POST"];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
//get response
NSString * requestST = [[request URL] absoluteString];
NSData * jsonData = [NSData dataWithContentsOfURL:[NSURL URLWithString:requestST]];
NSError *error;
//added check
if (jsonData!=nil) {
NSDictionary * dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
self.status = [dataDictionary objectForKey:#"status"];
self.balance = [dataDictionary objectForKey:#"result"];
//check status
if ([self.status isEqualToString:#"fail"]) {
NSLog(#"Fail")
}
else{
//assign variables
}
}
//if JSON is NIL
else{
NSLog(#"JSON Data is NIL");
}
//finish loading
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
}
The architecture of the app is the following:
HOME-->Login-->Sign Up
Therefore I cannot use viewDidLoad in the Home method for the JSON call because it crashes. I uses popToRootViewController when there is a successful login. Just incase anyone ask why I use viewWillAppear for the JSON call. If there are any alternatives do not hesitate to suggest :)
It is a synchronous task because I need the information to modify labels on the screen.
That's not a good excuse. If you run synchronous networking code on the main thread, you block the UI and the user interface hangs.
In viewDidLoad, set up your view hierarchy with whatever user interface is appropriate to show that the content is loading. Then, when your JSON finishes loading, update the user interface to show the content.
You are using NSURLConnection so it's simple approach is
So start MBProgrssHUD in the NSURLConnection delegate method
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
and stop MBProgrssHUD in the NSURLConnection delegate method
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
and
- (void)connectionDidFinishLoading:(NSURLConnection *)connection