UITextField: set text from a label - objective-c

I'm trying to write my first iPad app using Xcode 4: it's based on "Tabbed Application" template with two views. On the first view, user selects a City (label displays selection) and on the second wiew there is a IBOutletCollection(UITextField) NSArray *playersData. I want to set the city selected on first view as a default city on second view. I have checked storyboard connections and they seem to be ok.
I get nothing. Any idea?
First view :
#import
#interface pruebaF1FirstViewController : UIViewController
- (IBAction)selectCity:(UIButton *)sender;
#property (weak, nonatomic) IBOutlet UILabel *citySelected;
#end
First view implementation :
#import "pruebaF1FirstViewController.h"
#import "pruebaF1SecondViewController.h"
#interface pruebaF1FirstViewController ()
#property pruebaF1SecondViewController *secondView;
#end
#implementation pruebaF1FirstViewController
#synthesize citySelected;
#synthesize secondView;
- (void)viewDidLoad
...
- (IBAction)selectCity:(UIButton *)sender {
NSString *currentCity =[sender currentTitle];
citySelected.text=#"";
citySelected.text =[citySelected.text stringByAppendingString:currentCity];
/*writes null*/
secondView.defaultCity.text=[NSString stringWithFormat:#"%#" ,currentCity];
NSLog(#"%#",secondView.defaultCity.text);
}
#end
Second view header
#import <UIKit/UIKit.h>
#interface pruebaF1SecondViewController : UIViewController <UITextFieldDelegate>
#property (strong, nonatomic) IBOutletCollection(UITextField) NSArray *playersData;
#property (retain, nonatomic) IBOutlet UITextField *defaultCity;
- (IBAction)eraseData:(UIButton *)sender;
- (IBAction)savePlayersData:(UIButton *)sender;
- (IBAction)termsPopUp:(UIButton *)sender;
/*- (void)writeDefaultCity:(NSString *)currentCity;*/
#end
Second view implementation
#import "pruebaF1SecondViewController.h"
#import "pruebaF1FirstViewController.h"
#interface pruebaF1SecondViewController ()
#property (nonatomic, strong)pruebaF1FirstViewController *prueba;
#end
#implementation pruebaF1SecondViewController
#synthesize playersData;
#synthesize defaultCity;
#synthesize prueba;
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setPlayersData:nil];
[self setDefaultCity:nil];
[super viewDidUnload];
}
/* Return or Done button dismiss keyboard*/
-(BOOL)textFieldShouldReturn:(UITextField *)boxes
{
for (UITextField *boxes in playersData) {
[boxes resignFirstResponder];
}
return YES;
}
....
/*Trying to get city's name from first view in two ways*/
/*-(void)setDefaultCity
{
NSString *defecto=prueba.citySelected.text;
self.defaultCity.text = defecto;
}*/
- (IBAction)eraseData:(UIButton *)sender {
for (UITextField *boxes in playersData) {
boxes.text = #" ";
}
}
/*
-(void)writeDefaultCity:(NSString *)currentCity
{
defaultCity.text =[NSString stringWithFormat:#"%#" ,currentCity];
NSLog(#"Ciudad elegida: %#",currentCity);
}*/
....
#end

Views are generally not loaded until they are displayed on the device, and may be unloaded at any time when not visible to save memory. This means that when you're setting the 'text' property of the 'defaultCity', that label has not yet been created.
Instead you should add a NSString * property to pruebaF1SecondViewController and set the value of the defaultCity label in viewDidLoad:
In the header:
#property (nonatomic, weak) UILabel *defaultCityLabel;
#property (nonatomic, strong) NSString *defaultCity;
In the implementation
- (void)viewDidLoad
{
[super viewDidLoad];
defaultCityLabel.text = defaultCity;
}
And in the first view controller, assign the string value instead of the label value.

Related

KVO Method observeValueForKeyPath notifys me about the change, but I can't use it in viewDidLoad

I am working on this couple of days and I can't figure out what I am doing wrong.
First, I don't know if the KVO is the best way to pass the value of the clicked row info from one view controller to another view controller.
I have Main view, with 2 buttons only. Clicking on one of the buttons, I open MasterTableViewController, where I have the NSTableView with some records (one column only) from core data.
On click on the NSTableView, I am opening the DetailViewController, where I have only one label.
What I am trying is to change the label value, with the value of the clicked row in the NSTableView.
While I can print the value of the clicked row in the DetailViewController, I can't change the label value. I assume that notification comes before the viewDidLoad get called.
I have the following code:
In my MasterTableViewController.h file:
#import <Cocoa/Cocoa.h>
#import "AppDelegate.h"
#interface MasterTableViewController : NSViewController
#property (nonatomic,strong) NSManagedObjectContext *mObjContext;
#property (weak) IBOutlet NSTableView *websitesTableView;
- (IBAction)tableViewDoubleClick:(id)sender;
#property (nonatomic,strong) NSString *cellValue;
#end
In my MasterTableViewController.m file:
#import "MasterTableViewController.h"
#import "DetailViewController.h"
#interface MasterTableViewController ()
#end
#implementation MasterTableViewController
-(void)awakeFromNib {
[_websitesTableView setTarget:self];
[_websitesTableView setDoubleAction:#selector(tableViewDoubleClick:)];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Get the object managed context
AppDelegate *appDelegate = (AppDelegate*)[[NSApplication sharedApplication] delegate];
self.mObjContext = appDelegate.managedObjectContext;
}
- (IBAction)tableViewDoubleClick:(id)sender {
NSInteger rowNumber = [_websitesTableView clickedRow];
NSTableColumn *column = [_websitesTableView tableColumnWithIdentifier:#"websiteUrl"];
NSCell *cell = [column dataCellForRow:rowNumber];
_cellValue = [cell stringValue];
MasterTableViewController *mtvc = [[MasterTableViewController alloc]initWithNibName:#"MasterTableViewController" bundle:nil];
DetailViewController *dvc = [[DetailViewController alloc]initWithNibName:#"DetailViewController" bundle:nil];
[mtvc addObserver:dvc
forKeyPath:#"cellValue"
options:NSKeyValueObservingOptionNew
context:NULL];
[mtvc setCellValue:_cellValue];
[mtvc removeObserver:dvc forKeyPath:#"cellValue"];
AppDelegate *appDelegate = (AppDelegate*)[[NSApplication sharedApplication] delegate];
[appDelegate changeViewController:2];
}
#end
Code for the DetailViewController.h is:
#import <Cocoa/Cocoa.h>
#import "AppDelegate.h"
#interface DetailViewController : NSViewController
#property (nonatomic, weak) AppDelegate *appDelegate;
#property (weak) IBOutlet NSTextField *detailLabel;
#property (nonatomic,strong) NSString *transferedLabelValue;
#property (nonatomic,strong) NSString *cellValue;
#end
Code for the DetailViewController.m is:
#import "DetailViewController.h"
#import "MasterTableViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
- (void)viewDidLoad {
[super viewDidLoad];
// if I uncomment this line, program crashes, because the value of the _transferedLabelValue is null here.
//[_detailLabel setStringValue:_transferedLabelValue];
}
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if ([keyPath isEqualToString:#"cellValue"]) {
_transferedLabelValue = [change objectForKey:NSKeyValueChangeNewKey];
// Here I get the value of the clicked cell, it is printed in the console. However if I try to change the label value here, doesn't work, since seems that label does not exist yet at this point....
NSLog(#"Value in the observerValueForKeyPath is:%#",_transferedLabelValue);
}
}
#end
Code from the AppDelegate.h :
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (weak) IBOutlet NSView *mainAppView;
#property (nonatomic,strong) NSViewController *mainAppViewController;
- (IBAction)showMasterViewButtonHasBeenClicked:(id)sender;
- (IBAction)showDetailViewButtonHasBeenClicked:(id)sender;
- (void)changeViewController:(NSInteger)tag;
#end
Here is only the relevant code from the AppDelegatge.m, the boiler plate code is omited.
#import "AppDelegate.h"
#import "MasterTableViewController.h"
#import "DetailViewController.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
- (IBAction)saveAction:(id)sender;
#end
#implementation AppDelegate
- (IBAction)showMasterViewButtonHasBeenClicked:(id)sender {
NSInteger tag = [sender tag];
[self changeViewController:tag];
}
- (IBAction)showDetailViewButtonHasBeenClicked:(id)sender {
NSInteger tag = [sender tag];
[self changeViewController:tag];
}
- (void)changeViewController:(NSInteger)tag {
[[_mainAppViewController view]removeFromSuperview];
switch (tag) {
case 1:
self.mainAppViewController = [[MasterTableViewController alloc]initWithNibName:#"MasterTableViewController" bundle:nil];
[_mainAppView addSubview:[_mainAppViewController view]];
[[_mainAppViewController view] setFrame:[_mainAppView bounds]];
[[_mainAppViewController view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
break;
case 2:
self.mainAppViewController = [[DetailViewController alloc]initWithNibName:#"DetailViewController" bundle:nil];
[_mainAppView addSubview:[_mainAppViewController view]];
[[_mainAppViewController view] setFrame:[_mainAppView bounds]];
[[_mainAppViewController view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
break;
}
}
Again, if the KVO and notification is not the best way to go, please let me know how I should "inform" the other view which row has been clicked and which is his value.
Regards, John
I manage to solve my problem with the KVO...My problem was that I was creating new instances of the view controllers in the MasterTableViewController...What I did was I created properties for the ViewControllers in the appDelegatge.h like this:
#property MasterTableViewController *mtvc;
#property DetailViewController *dvc;
and then in the appDelegate.m :
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
_mtvc = [[MasterTableViewController alloc]initWithNibName:#"MasterTableViewController" bundle:nil];
_dvc = [[DetailViewController alloc]initWithNibName:#"DetailViewController" bundle:nil];
}
Rest of the changes in the code are just replacing the MasterTableViewController and DetailViewController with _mtvc and _dvc...
However...I had been warned that this solution is error prone, and that warning shows true. It happens from time to time that I get wrong value, not the clicked one. Once in 4-5 clicks, I get wrong value. What makes me confuse is that I make the function to work on double click, but it works on single click as well...But those things are for some other question I guess.

Can not set text for Label

In controller I have label property:
#interface BallsViewController : UIViewController <UIInteraction>
#property (weak, nonatomic) IBOutlet UILabel *ScoreLabel;
-(void)UpdateScore:(int)score;
#end
#interface BallsViewController ()
#end
#implementation BallsViewController
#synthesize ScoreLabel;
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)UpdateScore:(int)score
{
NSString *scoreStr =[NSString stringWithFormat:#"%d",score];
[self.ScoreLabel setText:scoreStr];
[self.InfoLabel setText:scoreStr];
}
#end
UpdateScore is protocol method. When I want to set text to ScoreLabel it have value : ScoreLabel UILabel * 0x00000000
It means that it is not initialize?
When I set text, on ui it not change.
Try setting your Label as Strong.
#property (strong, nonatomic) IBOutlet UILabel *ScoreLabel;

#protocol with integers

I am trying to make a protocol for a detail view for a tableView. The detail view has a question and then an answer. If I get the answer correct, it will set an integer to increase by 1 in a protocol method.
I am new to protocols and I don't understand what I am doing wrong.
Code
DetailViewController.h
Where the protocol is made
#import "Question.h"
#protocol DetailQuestionViewControllerDelegate <NSObject>
-(void)questionsCorrectHasChangedTo:(int)questionNumberChanged;
#end
#interface DetailQuestionViewController : UIViewController
#property (nonatomic, strong) Question *selectedQuestion;
#property (strong, nonatomic) IBOutlet UILabel *questionLabel;
#property (strong, nonatomic) IBOutlet UITextField *answerField;
#property (strong, nonatomic) IBOutlet UILabel *correctLabel;
#property (nonatomic,strong) id <DetailQuestionViewControllerDelegate> delegate;
#property (assign, nonatomic) int questionsCorrect;
DetailViewController.m
#implementation DetailQuestionViewController
#synthesize questionLabel;
#synthesize answerField;
#synthesize correctLabel;
#synthesize selectedQuestion;
#synthesize questionsCorrect;
#synthesize delegate;
- (void)viewDidLoad
{
[super viewDidLoad];
// Sets the questionLabel to the question we put in the array
self.questionLabel.text = [selectedQuestion questionName];
// Sets the navigation title to the rowName we put in the array
self.navigationItem.title = [selectedQuestion questionRowName];
NSLog(#"The question's answer for the question you selected is %#", [selectedQuestion questionAnswer]);
}
- (IBAction)checkAnswer:(UITextField *)sender
{
if ([[selectedQuestion questionAnswer] caseInsensitiveCompare:answerField.text] == NSOrderedSame)
{
// Show the correct label
[correctLabel setHidden:NO];
correctLabel.text = #"Correct!";
correctLabel.textColor = [UIColor greenColor];
*questionsCorrect = 1;
NSLog(#"questionsCorrect int is %d", questionsCorrect);
[self.delegate questionsCorrectHasChangedTo:questionsCorrect];*
}
else
{
// Show the incorrect label
[correctLabel setHidden:NO];
correctLabel.text = #"Incorrect";
correctLabel.textColor = [UIColor redColor];
}
// Erase the text in the answerField
answerField.text = #"";
}
ScoreViewController.h
Now here is my ScoreView which will be acsessing the delegate
#import <UIKit/UIKit.h>
#import "DetailQuestionViewController.h"
#interface ScoreViewController : UIViewController *<DetailQuestionViewControllerDelegate>*
#property (strong, nonatomic) IBOutlet UILabel *scoreLabel;
- (IBAction)resetButtonClicked:(UIButton *)sender;
-(void)checkScore;
#end
ScoreViewController.m
#import "ScoreViewController.h"
#import "DetailQuestionViewController.h"
#interface ScoreViewController ()
#end
#implementation ScoreViewController
#synthesize scoreLabel;
- (void)viewDidLoad
{
[super viewDidLoad];
*DetailQuestionViewController *dqvc = [[DetailQuestionViewController alloc] init];
dqvc.delegate = self;*
}
-(void)viewWillAppear:(BOOL)animated
{
[self checkScore];
}
-(void)checkScore
{
}
- (IBAction)resetButtonClicked:(UIButton *)sender
{
}
#pragma mark - DetailQuestionViewControllerDelegate -
*-(void)questionsCorrectHasChangedTo:(int)questionNumberChanged*
{
//set the textlabel text value to the number of questions correct
NSLog(#"questionsNumberChanged is %i", questionNumberChanged);
scoreLabel.text = [NSString stringWithFormat:#"You answered %d questions correctly",questionNumberChanged];
}
#end
The label is never updating for some reason.
Sorry for making the question so long, tried to be very specific.
I'm guessing somewhat here as you talk about increasing a value in a protocol method, yet you don't have a single + or ++ anywhere... You also have quite a few *'s sprinkled in strange places in your sample code, it is unclear whether these are typos, intended as emphasis, or intended to be pointer indirection.
So you have a property questionsCorrect in your DetailQuestionViewController class so let's assume this is the class you expect to own the counter (we'll skip that this is a view and not a model class...). If this is the idea then lines:
*questionsCorrect = 1;
NSLog(#"questionsCorrect int is %d", questionsCorrect);
[self.delegate questionsCorrectHasChangedTo:questionsCorrect];*
should be:
self.questionsCorrect++; // increment the counter
NSLog(#"questionsCorrect int is %d", self.questionsCorrect);
[self.delegate questionsCorrectHasChangedTo:self.questionsCorrect];
(you can also declare the instance variable questionsCorrect yourself and drop the use of self. above - whichever you prefer)
Now just go through and remove the other cases of extra *'s if they are in your code as well as the sample above and you'll be a bit closer to your goal.
If alternatively you wish ScoreViewController to own the counter then you need to declare it there and provide a method to increment and display it.
HTH

Passing data from a modal view

Storyboard
ViewController
SecondViewController
I'd like to pass data (aNumber, a variable NSString) in LabelNumber (in ViewController) from modal SecondViewController after entering numbers in TextFieldNumber using a decimal pad.
I add a close button (bar button item) in the SecondViewController and connect to Segue (mySegue).
In ViewController there's a Round Rect Button linked to SecondViewController
Here's the code in ViewController.m
#import "ViewController.h"
#import "SecondViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UILabel *LabelNumber;
#property (weak, nonatomic) SecondViewController * SecondScreen;
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString: #"mySegue"]){
self.SecondScreen = segue.destinationViewController;
self.SecondScreen.aNumber = self.LabelNumber.text
}
- (IBAction)close:(UIStoryboardSegue*)sender {
if([sender.identifier isEqualToString:#"mySegue"] ){
self.LabelNumber.text = self.SecondViewController.aNumber;
}
In SecondViewController.h i've this code:
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#property (strong, nonatomic) NSString* aNumber;
#end
In SecondViewController.m i've this code:
#import "ViewController.h"
#import "SecondViewController.h"
#interface SecondViewController () <UITextFieldDelegate>
#property (strong, nonatomic) IBOutlet UITextField *TextFieldNumber;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
[self.TextFieldNumber becomeFirstResponder];
self.TextFieldNumber.delegate = self;
self.TextFieldNumber.text = self.aNumber;
}
- (IBAction)getValue:(UITextField *)sender {
self.aNumber = self.TextFieldNumber.text ;
[self.TextFieldNumber resignFirstResponder];
}
At last, i've added always in SecondViewController.m that, even if i don't want to close the keyboard but i want it to stay always ON and would like to catch the TextNumber value (aNumber) in close button (modal unwind).
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
if (textField == self.TextFieldNumber)
[self.TextFieldNumber resignFirstResponder];
return YES;
}
If I understood the question correctly, you have two options:
Assign the FirstViewController as delegate of SecondViewController, so that when you dismiss modal you can also call [self.delegate secondViewControllerWillDismiss:value]
Make the FirstViewController listen for a custom notification, let's say "SecondViewControllerDismissNotification", and made SecondViewController send this NSNotification when dismiss. In this case you will have to write your parameter in a NSDictionary to be passed along with the notification itself.
If it's not clear I can write little example.

Delegation and Modal View Controllers

According to the View Controller Programming Guide, delegation is the preferred method to dismiss a modal view.
Following Apple's own Recipe example, i have implemented the following, but keep getting warnings that the addNameController:didAddName method is not found...
NameDelegate.h
#protocol NameDelegate
- (void)addNameController:(AddName *)addNameController didAddName:(NSString *)name;
#end
AddName.h
#interface AddName : UIViewController {
UITextField *nameField;
id delegate;
}
- (IBAction)doneAction;
- (id)delegate;
- (void)setDelegate:(id)newDelegate;
#property (nonatomic, retain) IBOutlet UITextField *nameField;
#end
AddName.m
- (IBAction)doneAction {
[delegate addNameController:self didAddName:[nameField text]];
}
- (id)delegate {
return delegate;
}
- (void)setDelegate:(id)newDelegate {
delegate = newDelegate;
}
ItemViewController.h
#import "NameDelegate.h"
#interface ItemViewController : UITableViewController <NameDelegate>{
}
#end
ItemViewController.m
- (void)addItem:(id)sender {
AddName *addName = [[AddName alloc] init];
addName.delegate = self;
[self presentModalViewController:addName animated:YES];
}
- (void)addNameController:(AddName *)addNameController didAddName:(NSString *)name {
//Do other checks before dismiss...
[self dismissModalViewControllerAnimated:YES];
}
I think all the required elements are there and in the right place?
Thanks
You haven't specified that the delegate property of AddName has to conform to the NameDelegate protocol.
Use this code in AddName.h:
#import "NameDelegate.h"
#interface AddName : UIViewController {
UITextField *nameField;
id <NameDelegate> delegate;
}
#property(nonatomic, retain) IBOutlet UITextField *nameField;
#property(nonatomic, assign) id <NameDelegate> delegate;
- (IBAction)doneAction;
#end