I have two views :
View1 (Shop) : URL stocked in NSString for displaying image.
View2 (ModifyShop) : Text field with URL from view1.
I can pass data from view1 to view2 : The URL stocked in NSString appears in Text field and pass data from view2 to view1. (URL for example)
Now I would like to modify this URL with Text field from view2 and that modify the NSString in view1 for ever. How can I make that ? Using NSUserDefaults ?
Here is my code :
Shop:
- (void)viewDidLoad {
[super viewDidLoad];
[self.modifyButton setHidden:YES];
}
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
if(![[NSUserDefaults standardUserDefaults] boolForKey:#"admin"]) {
NSLog(#"pas admin");
} else {
[self.modifyButton setHidden:NO];
}
dispatch_async(dispatch_get_global_queue(0,0), ^{
self.imageButtonURL = #"http://bundoransurfshop.com/wp-content/uploads/2015/02/72-torq-pink.jpg";
imageButtonData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:self.imageButtonURL]];
if ( imageButtonData == nil )
return;
dispatch_async(dispatch_get_main_queue(), ^{
self.imageButton.imageView.image = [UIImage imageWithData: imageButtonData];
});
});
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"modifyShop"]) {
ShopModify *viewcontroller = (ShopModify *)segue.destinationViewController;
viewcontroller.imageButtonURL = self.imageButtonURL; }
}
-(IBAction)prepareForUnwindShopModify:(UIStoryboardSegue *)segue {
NSLog(#"%#", self.imageButtonURL);
}
Shopmodify:
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.photoURL.text = [NSString stringWithFormat:#"%#", self.imageButtonURL];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
Shop *viewcontroller = (Shop *)segue.destinationViewController;
viewcontroller.imageButtonURL = self.photoURL.text;
}
You can store a URL string in NSUserDefaults by following this post:
Save string to the NSUserDefaults?
Simply have your view1 always get it from NSUserDefaults in viewWillAppear and have view2 change the NSUserDefaults key for the URL string and that should do it
If with foverer you mean even after you close and open again your app, replacing the default http://bundoransurfshop.com/wp-content/uploads/2015/02/72-torq-pink.jpg, yes, for example you could use NSUserDefaults (or any other persistent way to store your data/configuration).
Save on edit in view2:
[[NSUserDefaults standardUserDefaults] setObject:valueToSave
forKey:#"imageUrl"];
[[NSUserDefaults standardUserDefaults] synchronize]; //Important
Load/Reload in view1:
NSString *savedUrl = [[NSUserDefaults standardUserDefaults] stringForKey:#"imageUrl"];
if(!savedValue){
savedUrl = #"http://bundoransurfshop.com/wp-content/uploads/2015/02/72-torq-pink.jpg";
}
Official documentation for NSUserDefaults.
Related
I want to add image from Gallery/Camera to NSMutableDictionary & i am using following methods which i found Here
[dict setObject:UIImageJPEGRepresentation(chosenImage,0.5) forKey:#"image_four"];
[documents replaceObjectAtIndex:0 withObject:dict];
[tableOne reloadData];
In Cell for row at Indexpath
[cell.oneImgView setImage:[[UIImage alloc]initWithData:[dict objectForKey:#"image_four"]]];
I m adding NSMutableDictionary objects into one global array in ViewController A & Sending it to ViewController B where i add/update image from gallery/camera.
but when i press back button and go back UIViewController A and then again go to view controller B those images are still in that array.
In short, whenever i add image to Array of UIViewController B it some how affects to Array of UIViewController A.
I want this to be done on Done button click but if i click on back button of navigation bar it does the same as Done button.
- (IBAction)goToBack:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
Can someone tell me where i m going wrong?
Create another array and assign the ViewController array to this array
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
ViewControllerB *controllerb = [segue destinationViewController];
[controllerb setDocuments1:sender];
}
ViewControllerB.h
#property (nonatomic, strong) NSMutableArray *documents1;
ViewController.m
#import "ViewControllerB.h"
#import "UploadCell.h"
#interface ViewControllerB ()
{
NSArray *arrSavedObjects;
}
#end
#implementation ViewControllerB
#synthesize documents,documents1;
-(void)viewWillAppear:(BOOL)animated
{
arrSavedObjects = [[NSUserDefaults standardUserDefaults] objectForKey:#"arrayObjects"];
documents = [NSMutableArray arrayWithArray:arrSavedObjects];
if(documents.count==0)
{
documents = documents1;
}
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
UIImage *chosenImage = info[UIImagePickerControllerOriginalImage];
//NSMutableDictionary *dict = [documents objectAtIndex:selected];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[documents objectAtIndex:selected]];
if (![dict objectForKey:#"image1"]) {
[dict setObject:UIImageJPEGRepresentation(chosenImage, 0.5) forKey:#"image1"];
}
else{
[dict setObject:UIImageJPEGRepresentation(chosenImage, 0.5) forKey:#"image2"];
}
[documents removeAllObjects];
[documents addObject:dict];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:documents forKey:#"arrayObjects"];
[defaults synchronize];
[tableDocuments reloadData];
[controller dismissViewControllerAnimated:YES completion:nil];
}
Finally, solved by copying objects of NSObject class & adding it array.
[[controllerb setDocuments1]addObjectsFromArray:array];
I created a present modally segues in my storyboard like in the image below.
My First scene has a button with an action:
- (IBAction)loginButtonPressed:(id)sender {
[self Login];
}
which goes into this method:
- (void)Login
{
NSString *rawString = [self.idTextField text];
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
[self.idTextField setText:[rawString stringByTrimmingCharactersInSet:whitespace]];
[userName UserLogin:self.idTextField.text andPassWordExists:self.passwordTextField.text completionHandler:^(id responseObject, NSError *error) {
if (responseObject != nil) {
NSString *userN,*name;
NSArray *object = [responseObject objectAtIndex:0];
userN = [object valueForKey:#"userName"];
name = [object valueForKey:#"name"];
self.idTextField = nil;
self.passwordTextField = nil;
LHAppDelegate *appDelegate = (LHAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.loginSession setString:[userN lowercaseString]];
[appDelegate.nameOfUser setString:name];
}else{
[self CustomAlert:#"Sorry Login Failed, User and/or Passsword Incorrect"];
}
[indicatorView stopAnimating];
[indicatorView removeFromSuperview];
indicatorView = nil;
[loadingView removeFromSuperview];
loadingView = nil;
}];
}
What I am trying to do is program so when the user logins in they are present modally to the Tab Bar Controller.
Currently, when I click on the button with the wrong creds, I see my custom alert, but it still brings me to the Tab bar Controller.
Basically what I wanna do is put a condition around the present modally segues. Is this possible?
I found this piece of code:
[self performSegueWithIdentifier: #"MySegue" sender: self];
and I added it to my Login method:
- (void)Login
{
NSString *rawString = [self.idTextField text];
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
[self.idTextField setText:[rawString stringByTrimmingCharactersInSet:whitespace]];
[userName UserLogin:self.idTextField.text andPassWordExists:self.passwordTextField.text completionHandler:^(id responseObject, NSError *error) {
if (responseObject != nil) {
NSString *userN,*name;
NSArray *object = [responseObject objectAtIndex:0];
userN = [object valueForKey:#"userName"];
name = [object valueForKey:#"name"];
self.idTextField = nil;
self.passwordTextField = nil;
LHAppDelegate *appDelegate = (LHAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.loginSession setString:[userN lowercaseString]];
[appDelegate.nameOfUser setString:name];
[self performSegueWithIdentifier: #"MySegue" sender: self];
}else{
[self CustomAlert:#"Sorry Login Failed, User and/or Passsword Incorrect"];
}
[indicatorView stopAnimating];
[indicatorView removeFromSuperview];
indicatorView = nil;
[loadingView removeFromSuperview];
loadingView = nil;
}];
}
still when I login with the wrong creds and it still brings me to the Tab Bar Controller
In the above scenario it will always perform segue unaffected by server response because the segue is performed by button click.
To avoid this do it in the following way:
Delete the segue from button to the UITabBarController and make it
from view controller to the UITabBarController(drag from view
controller to other view conroller).
Now when your getting success in response make the following call
[self performSegueWithIdentifier:#"segueIdentifier" sender:self]
And if you want to pass parameters the perform the following function:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
One easy way of doing it would be to implement - (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender from the NSSeguePerforming protocol.
If user was not logged in return NO, else return YES, and segue will be performed/user will be taken to the tab bar controller.
EDIT
Since you already have implemented logic for authorising user in login method, I suggest doing what #manish_kumar have suggested.
When I login to my app, my app does push the ViewController XYZMainViewController, XYZMainViewController viewWillAppear:animated call method that makes a request to my API to retrieve the authenticated user data, at this time I update the text of a label to show the user name. When I logout the app, it returns me to the login ViewController, when I do login again with another user, XYZMainViewController label text contains the name of the previous user, without updating the label text.
XYZMainViewController.m
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:NO];
[self homeProfile];
}
- (void)homeProfile
{
[NXOAuth2Request performMethod:#"GET"
onResource:[NSURL URLWithString:#"http://{url}/users/userinfo"]
usingParameters:nil
withAccount:[XYZCommonFunctions user]
sendProgressHandler:nil
responseHandler:^(NSURLResponse *response, NSData *responseData, NSError *error){
NSDictionary *parsedData = [[NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error] objectForKey:#"data"];
_user = [parsedData objectForKey:#"user"];
[self.label setText:[NSString stringWithFormat:#"Welcome %#!", [_user objectForKey:#"username"]]];
}];
}
- (IBAction)logout:(id)sender {
XYZAppDelegate* appDelegate = (XYZAppDelegate*)[[UIApplication sharedApplication] delegate];
[appDelegate logout];
}
XYZAppDelegate.m
- (void)login
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *identifier = [prefs stringForKey:#"accountidentifier"];
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
NSString *viewIdentifier = #"WelcomeView";
if(identifier != nil){
NXOAuth2Account *account = [[NXOAuth2AccountStore sharedStore] accountWithIdentifier:identifier];
if(account != nil) {
viewIdentifier = #"MainView";
}
UIViewController *controller = [mainStoryboard instantiateViewControllerWithIdentifier: viewIdentifier];
[navigationController pushViewController:controller animated:NO];
return;
}
}
- (void)logout
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs removeObjectForKey:#"accountidentifier"];
[prefs synchronize];
for (NXOAuth2Account *a in [[NXOAuth2AccountStore sharedStore] accounts] ){
[[NXOAuth2AccountStore sharedStore] removeAccount:a];
}
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
[navigationController popToRootViewControllerAnimated:YES];
}
I need to reinitialize all data in XYZMainViewController.
Thank you.
Look like problem is related to fetching JSON Object. It is possible that everytime you have send same user to fetch user data. You are not using NSUserdefault object to display name, you are using value, which is return by JSON Object. According to me cause of error is "withAccount:[XYZCommonFunctions user]" line.
I would like to suggest, instead of using
-(void)viewWillAppear:(BOOL)animated {
you can use
- (void)viewDidLoad
so that your login action performed only when your LoginController loads,instead when LoginController appear.
New viewwillAppear look as given below -
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:NO];
[self.label setText:#""];
}
and ViewDidLoad -
- (void)viewDidLoad
{
[super viewDidLoad];
[self homeProfile];
}
Also check your json response, whether you are getting response success or error.According to response need to handle.
Hope this helps.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"CatagoryToSetDetail"]){
BYFSetsDetailViewController *controller = (BYFSetsDetailViewController *)segue.destinationViewController;
controller.workOut.catagory = catagory.text;
controller.workOut.excercise = excercize.text;
NSLog(#"passing the values %# \n and %# \n ",controller.workOut.catagory,controller.workOut.excercise);
}
for some reason controller.workOut.category is nil and i dont know how to fix it.
here is how i instantiated it in view did load
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.workOut = [[BYFWorkOut alloc]init];
NSLog(#"recieved values %# \n and %# \n ",_workOut.catagory,_workOut.excercise);
}
Thank you any help would be appreciated
prepareForSegue performed before viewDidLoad and yours workOut is nil when you tries assign category and excersize
Solution 1:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"CatagoryToSetDetail"]){
BYFSetsDetailViewController *controller = (BYFSetsDetailViewController *)segue.destinationViewController;
controller.workOut.catagory = catagory.text;
controller.workOut.excercise = excercize.text;
NSLog(#"passing the values %# \n and %# \n ",controller.workOut.catagory,controller.workOut.excercise);
}
in BYFSetsDetailViewController:
#implementation BYFSetsDetailViewController
#synthesyze workOut = _workOut;
- (id) initWithCoder:(NSCoder*) encoder
{
self = [super initWithCoder:encoder];
if (self)
{
_workOut = [[BYFWorkOut alloc] init];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"recieved values %# \n and %# \n ",_workOut.catagory,_workOut.excercise);
}
Solution 2:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"CatagoryToSetDetail"]){
BYFSetsDetailViewController *controller = (BYFSetsDetailViewController *)segue.destinationViewController;
controller.workOut = [[BYFWorkOut alloc]init];
controller.workOut.catagory = catagory.text;
controller.workOut.excercise = excercize.text;
NSLog(#"passing the values %# \n and %# \n ",controller.workOut.catagory,controller.workOut.excercise);
}
in BYFSetsDetailViewController:
#implementation BYFSetsDetailViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"recieved values %# \n and %# \n ",_workOut.catagory,_workOut.excercise);
}
Have you checked that category.text and exercise.text are not nil? - as those are the values you're passing to the destinationViewController in this method.
Also, where have you instantiated catagory.text and excercize.text ?
Edit
It looks like your custom object workOut has not been instantiated correctly. Do this in your init or viewDidLoad method of BYFSetsDetailViewController
Edit 2
Okay I got it work like this (Not sure why, maybe someone can explain more)
In your BYFSetsDetailViewController make a public property of NSString (I assume, workOut is an NSString?)
Then in your prepareForSegue method do this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"CatagoryToSetDetail"]){
BYFSetsDetailViewController *controller = (BYFSetsDetailViewController *)segue.destinationViewController;
controller.myString = catagory.text;
controller.myString2 = excercize.text;
NSLog(#"passing the values %# \n and %# \n ",controller.workOut.catagory,controller.workOut.excercise);
}
Declare your strings like this: #property (copy, nonatomic) NSString *myString
Then in your viewDidLoad method of BYFSetsDetailViewController
Do this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.workOut = [[BYFWorkOut alloc]init];
self.workOut.catagory = self.myString;
self.workOut.excercize = self.myString2;
NSLog(#"recieved values %# \n and %# \n ",_workOut.catagory,_workOut.excercise);
}
This should solve your issue.
Edit 3
From Cy-4AH's answer - do this in your prepareForSegue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"CatagoryToSetDetail"]){
BYFSetsDetailViewController *controller = (BYFSetsDetailViewController *)segue.destinationViewController;
controller.workOut = [[BYFWorkOut alloc]init];
controller.workOut.catagory = catagory.text;
controller.workOut.excercise = excercize.text;
NSLog(#"passing the values %# \n and %# \n ",controller.workOut.catagory,controller.workOut.excercise);
Remember to import BYFWorkOut in this viewController at the top of the file.
My First View is a UIViewController i have a UITable View in it and it works just fine.
From the first view i push another view, in that view i select a group name then the view dismiss, what i want is when i select the group name from the second view the first view loads the values of that group name to the table view, this is the code i use and its not working
the second view code
- (IBAction)sendNames:(id)sender {
if (!keyValue) {
NSLog(#"Didnt Select Any Group To Send");
return;
}
ViewController *theInstance = [[ViewController alloc] init];
[theInstance setGroupName:keyValue];
[theInstance ReceivedGroup:nil];
[self dismissViewControllerAnimated:YES completion:nil];
//tried that option and didnt work too, i added the rest of the code in the viewDidLoad
//[[NSNotificationCenter defaultCenter] postNotificationName:#"RG" object:nil];
}
keyValue is NSString that been set on tableView didSelectRowAtIndexPath
the first view
- (IBAction)ReceivedGroup:(id)sender {
NSString *path = [self dataFilePath];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSArray *tempArray = [dict objectForKey:groupName];
nameArray = [[NSMutableArray alloc] init];
[nameArray addObjectsFromArray:tempArray];
[nameTable reloadData];
NSLog(#"Group Name : %#",groupName);
NSLog(#"Array : %#",nameArray);
}
groupName is NSString
In the log i get the groupName and the nameArray printed
but the tableView is empty.
EDIT: I fixed the problem and posted my answer
Your viewcontroller "theInstance" will be deallocated immediately after calling sendNames: so nothing's gonna happen. You should rather pass a pointer of your first viewcontroller to your second viewcontroller (e.g. set it as a property) and perform all operations on this viewcontroller.
subclass UITableViewController
#interface SecondViewController : UITableViewController
#property (nonatomic, strong) ViewController *firstViewController;
#end
if using storyboard segues implement in your first viewcontroller :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
((SecondViewController *) segue.destinationViewController).firstViewController = self;
}
sendNames: should then look like this:
- (IBAction)sendNames:(id)sender {
if (!keyValue) {
NSLog(#"Didnt Select Any Group To Send");
return;
}
ViewController *theInstance = self.firstViewController;
[theInstance setGroupName:keyValue];
[theInstance ReceivedGroup:nil];
[self dismissViewControllerAnimated:YES completion:nil];
//tried that option and didnt work too, i added the rest of the code in the viewDidLoad
//[[NSNotificationCenter defaultCenter] postNotificationName:#"RG" object:nil];
}
I Fixed it by sending the keyValue using NSNotificationCenter
Here is my code now
For The Second View
- (IBAction)sendNames:(id)sender {
if (!keyValue) {
NSLog(#"Didnt Select Any Group To Send");
return;
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"RG" object:keyValue];
[self dismissViewControllerAnimated:YES completion:nil];
}
Then On The First View
- (void)receiveNotification:(NSNotification *)notification {
NSString *Key = [notification object];
nameArray = [[NSMutableArray alloc] init];
[nameArray removeAllObjects];
NSString *path = [self dataFilePath];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSArray *tempArray = [dict objectForKey:Key];
[nameArray addObjectsFromArray:tempArray];
[self.nameTable reloadData];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[nameTable numberOfRowsInSection:0] - 1 inSection:0];
[nameTable scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotification:) name:#"RG" object:nil];
}