Edit a UILabel from another Class (another ViewController) - ios

I want to edit a UILabel which is in ViewContrller2 from ViewController1.
This is my code, but it is not working:
ViewController1.m:
// ....
// In my viewDidLoad :
ViewController2 *vc = [[ViewController2 alloc]init];
// calling a function :
[vc updateLabel];
// ....
ViewController2.m:
// ....
-(void)updateLabel{
self.MyLabel.text = #"Text";
// MyLabel is already declared in ViewController2.h
}
// ....
Please can you help me?
I've tried many codes, but it's still not working and I don't know where the problem is.

Rightly or wrongly, to achieve this I would probably use NSUserDefaults to pull info between View Controllers.
ViewController1
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
[standardDefaults setObject:#"This is my Label" forKey:#"labelKey"];
ViewController2
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
MyLabel.text = [standardDefaults stringForKey:#"labelKey"]
Answer updated to reflect amended question for UIProgressView as per below comment:
ViewController1.m
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
[standardDefaults setDouble:0.75 forKey:#"ProgressValue"]; //value you want your progress view to show
ViewController2.h
...
create an outlet for your progress view here and link it up in IB
#property (weak, nonatomic) IBOutlet UIProgressView *ProgressView;
ViewController2.m
#synthesize ProgressView;
...
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
double ProgressValue = [standardDefaults doubleForKey:#"ProgressValue"];
ProgressView.progress = ProgressValue;

You're creating a new object of ViewController2 class,
if you want to set this value to all views you can use:-
1-NSUserDefaults
2-SQLite
3-Core Data
look to how pass data between view controllers :-
Passing Data between View Controllers

You are creating a new version of vc2, you need to access the one that already exists. Try sharing a reference to the vc2 controller in vc1 instead
You also need to think about whether you should update it directly from vc1 - you could refresh the label on viewDidLoad in vc2 instead
There are a number of options depending on how you have created vc1 & vc2, and there's a good description of the pros and cons here http://matteomanferdini.com/how-ios-view-controllers-communicate-with-each-other/

Make sure that before calling updateLabel on ViewController2 the viewDidLoad method of ViewController2 is called otherwise self.MyLabel will be nil and hence anything you assign to self.MyLabel.text will be useless. Now to ensure that viewDidLoad of ViewController2 gets called you need to access the view property of ViewController2 since viewDidLoad of a view controller is invoked when first time the view of the controller is tried to accessed.
Once viewDidLoad the things you intend to do will work for sure.
To confirm that this is indeed the problem, keep a breakpoint in the -(void)updateLabel method and analyze the to see if self.MyLabel is nil or not.

Related

Objecitive C - How to send SecondVC label text to FirstVC and update the FirstVC label text

In my case there are two ViewControllers. In my first view controller there is a label and when view load, it's text should display as 1. then there is a button, when it click,navigate to second view controller. In the second view , there is a stepper and label. If user tap + ,second view's label text change from 1 to 9,for the - also same(decrease the value). in the second view also there is a button.when it click, second view dismiss (from the first view to second I used presend Modally kind segue with over Current Context presentation.that means when dismiss this secondview, firstview does not load again,it exists in the background). so what I want is to send the second view's label text (after changed by the stepper), as first view's text and update the first view's label.(think if the second view's label text is 3, first view's label text should update from 1 to 3 ). I tried with NSUserdefaults.this is my code.
this is my second view controller
- (void)viewDidLoad {
[super viewDidLoad];
//set default value for adult label
NSUInteger defaultAdultVal = self.adultstepper.value;
self.adultcountLabel.text = [NSString stringWithFormat:#"%d", defaultAdultVal];
}
- (IBAction)adultcountAction:(UIStepper *)sender {
NSUInteger adultVal = sender.value;
self.adultcountLabel.text = [NSString stringWithFormat:#"%d", adultVal];
NSString *adultCount = [NSString stringWithFormat:#"%d", adultVal];
[[NSUserDefaults standardUserDefaults] setObject:adultCount forKey:#"adultcount"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (IBAction)DoneAction:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
and this is my second view controller
- (NSString *)testingAsign
{
NSString *adltCount = [[NSUserDefaults standardUserDefaults] objectForKey:#"adultcount"];
return adltCount;
}
I'm getting the value with this method in the first view, and I want to update first view's value but it didn't work.
There are many ways to this are
By using protocol-delegate - Perfect way
proper and perfect way it to create protocol for it in secondVC, and add one weak property as delegate, and while presenting secondVC.. assign firstVC as delegate of secondVC. Also, Implement that protocol in firstVC. Now when you are dismissing secondVC, call the method in protocol. And implemented method in firstVC get called.. so you get the value there.
By using NSNotification
You can add observer for notification in firstVC and postNotification from secondVC. But this is not proper way.. as firstVC continuously observes for notification. (Don't forget to remove observer.. once you dont require observation)
By using Global variable
You can add one global variable in appDelegate, and assign its value from secondVC. And access that value from firstVC. This is also not proper way. Because that variable always remain in memory.
Trying adding value from userdefault in view will appear in first view controller when second view controller dismiss after setting value in NSUserDefaults.
- (void) viewDidLoad:(BOOL)animated{
[super viewDidLoad:animated];
[[NSUserDefaults standardUserDefaults] #"1" forKey:#"adultcount"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
myStaticLabel.text = testingAsign;
}
- (NSString *)testingAsign
{
NSString *adltCount = [[NSUserDefaults standardUserDefaults] objectForKey:#"adultcount"];
return adltCount;
}
this can be done with so many ways like using delegate methods coredata , nsnotifications and nsuserdefaults. from all these , one of the easiest way to pass data backward, we can easily use NSUserDefaults. this is a sample project of passing data backwark using nsuserdefaults. use this github project and give it a try. project url : pass data backward using NSUserDefaults in ios, objective C
You don't need NSUSerDefaults for this. If all you want to do is to be able to transfer data on segue, you need to use the prepareForSegue function. Check out https://stackoverflow.com/a/7865100/2465172
In which method are you updating in FirstViewController, ViewDidLoad or ViewWillAppear Method? Do [[NSUserDefaults standardUserDefaults] #"1" forKey:#"adultcount"];[[NSUserDefaults standardUserDefaults] synchronize]; in SecondViewController and when you dismiss SecondViewController,get updated value from NSUserDefaults in ViewWillAppear Method of FirstViewController.Hope it will work.

Pass data between 2 views without segues

I have 2 views, a login view and a main view.
I use SWRevealViewController, and I want automatically display my menu at the startup of the app. I know how display my menu but I don't know how display it just once at startup.
I want to pass a simple String between my Login view and my Main view but without segue, and made a simple test :
if (myPreviousView == "LoginView")
{
// display my menu
}
Another method would be to use NSUserDefault to store your string, which than can be accessed from anywhere within the application.
So, you put your string into NSUserDefaults in your first view:
// Initialize the NSUserDefaults object and an array for data storage
NSUserDefaults *defsData = [NSUserDefaults standardUserDefaults];
NSMutableArray *myArray = [[NSMutableArray alloc] init];
// Add your string to the custom array
NSString *myString = #"My string.";
[myArray addObject:myString];
// Put the array back into UserDefaults for later use
[defsData setObject:myArray forKey:#"Key"]; // Key can be anything
[defsData synchronize];
Now, the array (and the string in it) is available anywhere. So, when you navigate to your second view controller, just initialize an NSUserDefaults and access the string:
NSUserDefaults* defsData = [NSUserDefaults standardUserDefaults];
NSArray *myArray = [defsData objectForKey:#"Key"];
NSLog("This is my stored string: %#", [myArray objectAtIndex:0]);
You can modify the init method of your second view controller to take a custom attribute when you subclass it. So, lets say you created a standard UIViewController (.h and .m files). You can modify the init method of this new class to your liking in the .h file:
- (instancetype)initWithString:(NSString *)string;
And then replace the standard init with the new one in the .m:
- (instancetype)initWithString:(NSString *)string {
}
So, when you call your view controller into existence, you just use this new init method and pass the string you wanted like this:
UIViewController *viewController = [[UIViewController alloc] initWithString:myString];
[self presentViewController:viewController animated:NO completion:nil];
This is a programmatical approach of course, but it should be applied to interface builder easily (unfortunately, as I never use interface builder, I don't know how exactly, but as I said, it should be fairly straightforward to anyone who uses it).

Using Storyboard to insert row in table view

I have 3 view controllers.
Navigation Controller - N
Table View Controller - T
Custom View Controller - C
Their layout is like so:
N -(root view controller)-> T -(bar button item Add - Triggered Segue)-> C
Just to clarify, T has an "Add" button which has a triggered segue action to present C modally.
C and T both have custom classes. C is a simple UIViewController subclass while T is a UITableViewController subclass.
In T I declare an NSMutableArray and a UITableView like so:
#interface T: UITableViewController {
NSMutableArray *myTableData;
IBOutlet UITableView *myTableView;
}
In C I have two elements within:
A UITextField
A UIButton called "send"
I connect the text field to an IBOutlet like so in C's header, as well as create an action for the button:
#interface C: UITableViewController {
IBOutlet UITextField *itemToAdd;
}
-(IBAction)addItem:(id)sender;
So I have the data array myTableData which populates T's table declared and initialized in T (I will add a myTableData = [[NSMutableArray alloc] init] in the viewDidLoad method of T.
When the "add" button in the navigation bar of T is clicked it will obviously bring up C and take in some text from the text field.
Then finally when the send button is pressed I want to add that text from the text field into the myTableData array, dismiss C (which I plan on doing with [self dismissViewControllerAnimated:YES completion:nil], and update the table view myTableView to reflect the changes that I have made.
Does anyone have any idea on how I could accomplish this? Mainly I need help somehow accessing myTableData (that lives in T) FROM C. Then I need to get T to recognize that some change has been made and to redraw its cells (probably by instigating cellForRowAtIndexPath). I am aware of how to do this all hardcoded Apple's docs, but I find that method isn't viable if you want to visually represent everything in the storyboard and they do not explain what everything means exactly (like itemInputController for instance).
If my approach is totally incorrect and I don't need all these classes or methods or am doing it all wrong, please feel free to give me a similar approach using the storyboard.
Create an NSMutableArray and store it in your NSUserDefaults. Here's how:
In your C - UIViewController, on the send button IBAction :
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = [defaults objectForKey:#"data"];
[arr addObject:WHATEVER_YOU_WANT_TO_ADD];
[defaults setObject:arr forKey:#"data"];
[defaults synchronise];
You can use this same method in T!

A UIlabel issue: Keep the string value after app is closed?

So one of the users in here managed to show me how to pass data from a child view controller to a parent view controller via a string.
So now the string is passed, BUT, i want that value to stay displayed on the firstViewController after the app is closed and re-opened.
The value is saved in with NSUserDefaults by the way and with an NSLog i am seeing on the conosole it is saved in the apps folder but that value isnt saved onto the UILabel display.
It only displays it when i put save but then i close and reopen, it dissappears but in an NsLog it is still inside the app but not on display UILabel.
How can i address this ?
On my appDelegate.h i have a
#property (strong, nonatomic) NSString *sharedString;
To pass the secondViewController data to the firstViewController.
In the save method on my secondViewController i have a function related to the
AppDelegate.h declaration which is:
AppDelegate *apiDelegate = [[UIApplication sharedApplication] delegate]
apiDelegate.sharedString = self.textFieldData.text;
And in my firstViewController i have a method which display the data from the second
viewController:
-(void) viewDidAppear:(BOOL)animated {
AppDelegate *apiDelegate = [[UIApplication sharedApplication] delegate]
self.DisplayData.text = appDelegate.sharedString;
[super viewDidAppear: NO];
Is there something wrong which isnt keeping the data intact after app closes or am
I missing something here ?
So one of the users in here managed to show me how to pass data from a
child view controller to a parent view controller via a string.
First you need to establish some hierarchy as to how you get a childViewController from a parentViewController. One way to pass data from childViewController to parentViewController is using a delegate. The other could be using the KVC/KVO protocol. https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html
In this you can simply register an observer for the property defined in the childViewController and observe it's changes wherever you want (well, given the hierarchy is satisfied).
To save the value. You can simply save it using NSUserDefaults. I don't see any code in your post but you can simply define a key and save the value with NSUserDefaults using:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:sharedString forKey:#"sharedString"];
NSString *sharedStringFromDefaults = [defaults objectForKey:#"sharedString"];
Also,
AppDelegate *apiDelegate = [[UIApplication sharedApplication]
delegate]
Apple requires you to avoid such references in the application. It only constrains the app. Further, the sharedString is not required to be in the AppDelegate. Otherwise the AppDelegate will be filled with almost every other data structure you have shared in the app.
//add this code when you want to store string
[[NSUserDefaults standardUserDefaults] setObject:self.textFieldData.text forKey:#"sharedString"];
[[NSUserDefaults standardUserDefaults] synchronize];
//and when you want string than
self.DisplayData.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"sharedString"];

How do a ViewController knows it got focus on iOS? Like a "viewDidLoad"

I have a NavigationController and one of the tabs is supposed to load a ViewController.
This ViewController (1), when loaded on "viewDidLoad" does some stuff and then pushes a new ViewController (2). The thing is that after ViewController (1) has already passed through viewDidLoad, it won't pass through it again, unless the app is restarted.
Could you guys please refer a clever way to to this?
Here's what I am really doing:
- (void)viewDidLoad
{
// Keep track of cash using NSUserDefaults
BOOL dreceived[63];
int rightData;
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
//Load cash switches
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSData *data = [prefs objectForKey:#"dreceived"];
memcpy(&dreceived, data.bytes, data.length);
for(int n = 72; n >= 1; n = n - 1)
{
if(dreceived[n-1]==1)
{
rightData = n;
}
}
NSLog(#"Right Data %d", rightData);
CashItem *c = [cashflow objectAtIndex:rightData];
// Go for details
CashDetailedViewController *cdetail = [[[CashDetailedViewController alloc] init] autorelease];
cdetail.cash = c;
cdetail.navigationItem.hidesBackButton = YES;
[self.navigationController pushViewController:cdetail animated:YES];
}
The thing is, this code is never called again. And if I touch the tab twice, a blank view is displayed (th original xib view).
Thanks!
It sounds like you would want to use viewWillAppear. It is called every time that your view controller is about to be onscreen.
Although, based on what you've posted, you may want to rethink what your doing. Having a view controller that immediately presents another view controller should like it would lead to a confusing user experience.
Put your code in - (void)viewWillAppear instead
Try calling
[yourViewController.view setNeedsDisplay];
Or you could spin the code out to a seperate method and call it in viewDidLoad and viewDidAppear:animated

Resources