Not Updating Label From Different View Controller using NSUserDefaults - ios

I am trying to update a label on view controller (DropPinVC) by pressing a button on different view controller 2 (TypeLocation).
In DropPinVC.m I have:
- (void)viewDidLoad
{
TypeLocation *VC2 = [[TypeLocation alloc] initWithNibName:#"TypeLocation" bundle:nil];
VC2.myVC2 = self;
[super viewDidLoad];
}
In TypeLocation.h I have:
#property (nonatomic, strong) DropPinVC *myVC2;
In TypeLocation.m I have:
-(IBAction) switchValueChanged
{
if (self.TASwitch.on){
TypeLocation = #"Tourist Attraction";
[[NSUserDefaults standardUserDefaults] setObject:TypeLocation forKey:#"Type Location"];
}
else {
TypeLocation = #"Unsafe Location";
[[NSUserDefaults standardUserDefaults] setObject:TypeLocation forKey:#"Type Location"];
DropPinVC *myVC2 = [[DropPinVC alloc] initWithNibName:#"DropPinVC" bundle:nil];
NSString *updatedLabel = [[NSUserDefaults standardUserDefaults] stringForKey:#"Type Location"];
NSLog(#"Updated Label = %#", updatedLabel);
myVC2.TypeLabel.text = updatedLabel;
[self closeScreen];
}
However, the label on view controller 1 does not update. Does anybody know a solution to this problem? Thank you for your help!

You need to pass the string, updateLabel, to a string property you create in DropPinVC, and have that controller populate its label in viewDidLoad. Your approach doesn't work because the view hasn't loaded yet at the time you try to set the label's text, so myVC2.TypeLabel will be nil.
Also, you're not using your property, myVC2 in TypeLocation. this line,
DropPinVC *myVC2 = [[DropPinVC alloc] initWithNibName:#"DropPinVC" bundle:nil];
should be,
self.myVC2 = [[DropPinVC alloc] initWithNibName:#"DropPinVC" bundle:nil];

Related

How to save a rating control value?

I am playing around with DYRateView....a control at the end of a long list of controls I've tried out. It can be found here: https://github.com/dyang/DYRateView
The problem with all the controls I've tried is that I can't seem to save the rating once it's been changed. I'm using NSUserDefaults and have tried placing it in various places including where the value changes, where the view is set up, in viewDidLoad, in viewWillAppear, within the source code itself. Saving this value just has me flummoxed. I would appreciate any help. Just to get a sense of how this should work, I've just been working in the sample code that came with DYRateView. Here is the relevant code:
THE .M FILE
#import "DemoViewController.h"
#interface DemoViewController ()
- (void)setUpEditableRateView;
#end
#implementation DemoViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSUserDefaults standardUserDefaults] integerForKey:#"rating"];
[self setUpEditableRateView];
}
- (void)setUpEditableRateView {
DYRateView *rateView = [[DYRateView alloc] initWithFrame:CGRectMake(0, 40, self.view.bounds.size.width, 20) fullStar:[UIImage imageNamed:#"StarFullLarge.png"] emptyStar:[UIImage imageNamed:#"StarEmptyLarge.png"]];
rateView.padding = 20;
rateView.alignment = RateViewAlignmentCenter;
rateView.editable = YES;
rateView.delegate = self;
[self.view addSubview:rateView];
[rateView release];
}
- (void)rateView:(DYRateView *)rateView changedToNewRate:(NSNumber *)rate {
self.rateLabel.text = [NSString stringWithFormat:#"Rate: %d", rate.intValue];
[[NSUserDefaults standardUserDefaults] setInteger:rate forKey:#"rating"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
#end
Thanks to anyone who takes the time!
You are trying to save an NSNumber as an NSInteger. You should do [[NSUserDefaults standardUserDefaults] setInteger:[rate integerValue] forKey:#"rating"]; or use - setObject:forKey: because NSNumber is an object, not a scalar.
You are getting rating valuea at: [[NSUserDefaults standardUserDefaults] integerForKey:#"rating"]; but what are you doing with this value?
I think that you need to get this value and set to DYRateView. So:
Create a property of DYRateView: #property DYRateView * rateView
Set it on setUpEditableRateView: self.rateView = [[DYRateView alloc] initWithFrame:CGRectMake(0, 40, self.view.bounds.size.width, 20) fullStar:[UIImage imageNamed:#"StarFullLarge.png"] emptyStar:[UIImage imageNamed:#"StarEmptyLarge.png"]];
Update self.rateView (add it to end of setUpEditableRateView): rateView.rate = [[NSUserDefaults standardUserDefaults] integerForKey:#"rating"]

AVSpeechSynthesizer is not letting View Controller Deallocate

I have a view controller and in the .h I have:
{
NSString* textToSpeak;
}
#property (nonatomic, strong) AVSpeechSynthesizer* synthesizer;
In the .m of my view controller, I am using the synthesizer to play and pause a pre made script I created.
For example:
-(void)userProfileData:(UserProfileData *)userProfileData didReceiveDict:(NSDictionary *)dict
{
NSDictionary* resultsDict = [dict valueForKey:#"result"];
textToSpeak = [resultsDict objectForKey:#"text"];
UIBarButtonItem* pauseItem = [self.navigationItem.rightBarButtonItems objectAtIndex:0];
[pauseItem setEnabled:YES];
[self startSpeaking];
}
-(void)startSpeaking
{
if (!self.synthesizer) {
self.synthesizer = [[AVSpeechSynthesizer alloc] init];
self.synthesizer.delegate = self;
}
[self speakNextUtterance];
}
-(void)speakNextUtterance
{
AVSpeechUtterance* nextUtterance = [[AVSpeechUtterance alloc] initWithString:textToSpeak];
nextUtterance.rate = 0.25f;
[self.synthesizer speakUtterance:nextUtterance];
}
Before I created this synthesizer, I would navigate back to the parent view controller and dealloc would be called (I have a log statement in it to make sure it is called). However, as soon as I added this synthesizer, the dealloc is no longer being called. I am wondering why this is happening and how I can fix it. Any help would be amazing, thanks!
Solved the problem.. #ChrisLoonam you were a great help in the end. I just needed to stop the synthesizer beforehand and everything was deallocated properly

How to Update Label From Different View Controller using NSUserDefaults

I am trying to update a label on view controller 1 by pressing a button on different view controller 2. I have this IBAction in the view controller 2:
- (IBAction)done:(id)sender {
DropPinVC * vc = [[DropPinVC alloc]init];
NSString *updatedLabel = [[NSUserDefaults standardUserDefaults] stringForKey:#"Type Location"];
NSLog(#"Updated Label = %#", updatedLabel);
vc.TypeLabel.text = updatedLabel;
[self closeScreen];
}
However, the label on view controller 1 does not update. Does anybody know a solution to this problem?
vc is a new instance of DropPinVC class declared in the scope of the action posted, and is not the same instance as the one you want to update.
One way to achieve this is to keep a pointer to the first view controller.
In order for viewController2(vc2) to update a UILabel that is owned by viewController1(vc1), vc2 needs a reference to vc1 so it can access the label.
Add a property to vc2 of type DropPinVC
#property (nonatomic, strong) DropPinVC *vc1Ref;
Assuming vc1 allocates and initialises vc2 then where after this happens assign the vc1Ref property.
vc2.vc1Ref = self;
Now in the IBAction, your code can now access the correct instance and update the correct label.
- (IBAction)done:(id)sender {
NSString *updatedLabel = [[NSUserDefaults standardUserDefaults] stringForKey:#"Type Location"];
NSLog(#"Updated Label = %#", updatedLabel);
self.vc1Ref.TypeLabel.text = updatedLabel;
[self closeScreen];
}

Object of array in new ViewController keeps empty

I've a problem with an array.
There's an array with some objects of the class Car in my CarViewController:
...Car.h
#interface Car : NSObject
#property (nonatomic, strong) NSString *name;
..and Car.m
- (void)encodeWithCoder:(NSCoder *)coder;
{
[coder encodeObject:name forKey:#"name"];
}
- (id)initWithCoder:(NSCoder *)coder;
{
self = [[Car alloc] init];
if (self != nil)
{
name = [coder decodeObjectForKey:#"name"];
}
return self;
}
and CarViewController
Car *car1 = [Car new];
car1.name = #"A1";
...
cars = [NSArray arrayWithObjects: car1, car2, ..., nil];
But when I now try to have access to this array in NewViewController there is a problem:
- (IBAction)btn:(id)sender {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
CarViewController *vc = (CarViewController *)[storyboard instantiateViewControllerWithIdentifier:#"CarVC"];
Car *car = [vc.cars objectAtIndex:0];
NSLog(#"%#", car.name);
}
But in the log is just written that car.name = (null).
Thanks in advance to your effort.
UPDATE:
- (IBAction)btn:(id)sender {
UINavigationController *nav = self.tabBarController.viewControllers[1];
CarViewController *vc = nav.topViewController;
Car *car = [vc.cars objectAtIndex:0];
NSLog(#"%#", car.name);
}
I've tried something (thanks to rdelmar for his effort), but the result is still the same.
if you put this code
Car *car1 = [Car new];
car1.name = #"A1";
...
cars = [NSArray arrayWithObjects: car1, car2, ..., nil];
in the viewDidLoad method of your view controller, the the result is normal because your view is not loaded yet. (the viewDidLoad method has not been called yet)
I'm not familiar with storyboards but I think when you call
CarViewController *vc = (CarViewController *)[storyboard instantiateViewControllerWithIdentifier:#"CarVC"];
it will instantiate a new ViewController. So if you try to access cars property it will be nil if this new viewController is not presented on screen
Apple Documentation
You use this method to create view controller objects that
you want to manipulate and present programmatically in your
application. Before you can use this method to retrieve a view
controller, you must explicitly tag it with an appropriate identifier
string in Interface Builder.
This method creates a new instance of the specified view controller
each time you call it.

Property getting set then reset in init

Here's the property declaration in my SlidingVC header, a subclass of UITableViewController:
#property (strong, nonatomic) NSString *user;
Here's my synthesize line:
#synthesize user = _user,sortedWordlist = _sortedWordlist, wordlist = _wordlist;
Here's my custom init:
- (id)initWithUser:(NSString*)theUser
{
self = [super init];
if (self) {
if ([theUser isEqualToString:#"user"]) {
_user = #"user";
}
else if ([theUser isEqualToString:#"opponent"]){
_user = #"opponent";
}
}
return self;
}
So what's happening is that as I step pver initWithUser:, I see that _user takes on the memory address of theUser in the variable debugger window. I step over return self and then to the closing } of the method and it's still set. However, Xcode returns to return self one more time and then if I step over that _user doesn't have a memory address next to it anymore, and it remains null for the methods that follow.
Why is it returning twice and then setting to null the second time?
Here's the method in my MainVC that instantiates the SlidingVC:
- (WSWordlistTableViewController *)setupWordlistTableViewController:(NSString*)user
{
WSWordlistTableViewController *wordlistTableViewController;
UIView *wordlistContainerView;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle: nil];
if ([user isEqualToString:#"user"]){
if(!self.userWordlistTableViewController){
self.userWordlistTableViewController = [[WSWordlistTableViewController alloc] initWithUser:#"user"];
wordlistTableViewController = self.userWordlistTableViewController;
wordlistContainerView = self.userWordlistContainerView;
}
}
else if ([user isEqualToString:#"opponent"]) {
if(!self.opponentWordlistTableViewController){
self.opponentWordlistTableViewController = [[WSWordlistTableViewController alloc] initWithUser:#"opponent"];
wordlistTableViewController = self.opponentWordlistTableViewController;
wordlistContainerView = self.opponentWordlistContainerView;
}
}
wordlistTableViewController = [mainStoryboard instantiateViewControllerWithIdentifier:#"wordlistTableViewController"];
wordlistTableViewController.view.frame = wordlistContainerView.bounds;
wordlistTableViewController.view.autoresizingMask = wordlistContainerView.autoresizingMask;
[self addChildViewController:wordlistTableViewController];
[wordlistContainerView addSubview:wordlistTableViewController.view];
[wordlistContainerView bringSubviewToFront:wordlistTableViewController.wordlistTableView];
[wordlistTableViewController didMoveToParentViewController:self];
return wordlistTableViewController;
}
And the method that calls that, depending on which button is pressed:
- (IBAction)slideUserWordlistView:(id)sender {
if(!self.userWordlistTableViewController){
[self setupWordlistTableViewController:#"user"];
}
// (sliding drawer code here)
}
Or:
- (IBAction)slideOpponentWordlistView:(id)sender {
if(!self.opponentWordlistTableViewController){
[self setupWordlistTableViewController:#"opponent"];
}
// (sliding drawer code here)
}
What I'm doing is sliding out a view that contains my SlidingVC. I have two of them, one for each of two users. When each respective button is pressed I check if each respective SlidingVC exists, if not, instantiate then add to the the slidingViewContainer.

Resources