Having Trouble With UITextField and NSString - iphone

I have the following code for UITextField. The problem I'm having is that the text does not persist. For example, when I present a modal view, then dismiss it, the UITextField does not have the text anymore in it. I want the text to remain there until I dimiss that view with the text field.
I am displaying the UITextField like this:
UITextField *nameTextField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
nameTextField.delegate = self;
[nameTextField addTarget:self action:#selector(editingEnded) forControlEvents:UIControlEventEditingDidEnd];
[nameTextField setEnabled: YES];
self.myTextField = nameTextField;
[nameTextField release];
Then I have:
- (void)editingEnded
{
NSString *tempRoutineName = self.myTextField.text;
self.routineName = tempRoutineName;
[tempRoutineName release];
}

Instead of editingEnded, Implement the UITextFieldDelegate protocol. Go to the textFieldDidEndEditing method and reassign the value of text in it.
Like,
-(void) textFieldDidEndEditing:(UITextField *)textField{
if (textField.tag ==0){
self.myTextField = textField;
// myTextField is a property
}
Now in the in the viewDidLoad method or the viewWillAppear method, go ahead and assign this value back to the textField.
If necessary use [tableView reloadData] if this is used in a tableView or use [self reloadInputViews] (if necessary).
Then again, its all logical. Nothing too complex in code.

Use UITextFieldDelegate method that is textFieldDidEndEditing, which gets called when editing ends

In my opinion:
NSString *tempRoutineName = self.myTextField.text;
self.routineName = tempRoutineName;
[tempRoutineName release];
You haven't own tempRoutineName to release. Comment out the release and check.

Related

app crashes when I change the time on a date picker

I made an app with a textview that when you tap it, a date picker comes up. Is it something wrong with my code?
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(112, 88, 97, 30)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
[self.view addSubview:textField];
UIDatePicker *datePicker = [[UIDatePicker alloc] init];
datePicker.datePickerMode = UIDatePickerModeDate;
[datePicker addTarget:self action:#selector(datePickerValueChanged:) forControlEvents:UIControlEventValueChanged];
[textField setInputView:datePicker];
I am getting the error 2013-08-04 20:38:54.249 Habit Pal[7252:c07] -[SleepModeViewController datePickerValueChanged:]: unrecognized selector sent to instance 0x8840d70
You need to add a "datePickerValueChanged:" method to your SleepMoveViewController.h & .m file.
If you don't have one, then you should create one.
And if you have one, check to make certain it's the right API signature. For example:
- (void) datePickerValueChanged: (id) sender;
As you know you dont have a value for -(void)datePickerValueChanged, You can put this anywhere below in the file.
Basically you would create something like this:
-(void)datePickerValueChanged:(id)sender{
//Put what you want to occur whan the value changes
}
Add this method in your SleepModeViewController
-(void) datePickerValueChanged:(UIDatePicker*) datePicker {
//write your code here
}

Programmatically instantiating a Delegate to a component

I have an app which has a controller which already handles UITextFieldDelegate for textfields, now I want to add a second controller + UITextField programmatically which is separately from the main controller but is called from it.
So I have a MainController which handles input (that is working), then next to that, I defined this:
#interface TestUIDelegate : UIViewController <UITextFieldDelegate>{
TestUIDelegate has a property textField.
TestUIDelegate has a method:
- (void)initGUI:(UIView *)myView;
which initialises a textField like thus:
- (void)initGUI:(UIView *)myView {
self.view = myView;
textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 200, 300, 40)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.font = [UIFont systemFontOfSize:15];
textField.placeholder = #"enter text";
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.keyboardType = UIKeyboardTypeDefault;
textField.returnKeyType = UIReturnKeyDone;
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.delegate = self;
[self.view addSubview:textField];
}
which also works; the field shows up and is editable, keyboard comes up and you can type stuff.
So far so good, but now I want to Done button to work so the keyboard is dismissed, so I added:
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
NSLog(#"Here?");
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField{
NSLog(#"Or here?");
}
To my TestUIDelegate (actually I added all delegate methods from TextUIFieldDelegate).
I instantiate the TestUIDelegate from the didFinishLaunchingWithOptions in the MainController like this:
TestUIDelegate *controller = [[TestUIDelegate alloc] init];
[controller initGUI:self.view];
TextField still shows up the delegate methods are never called, none of them. Now I imagine i'm doing something very weird and I have looked through all answers on SO and in Google slightly relating to this, but they all do it by implementing the delegates in the MainController which is exactly what I really do not want. And I need it programmatically; not (at all) with the gui builder.
Can anyone enlighten me please? I don't think i'm going to figure this out on my own.
You need to add textFieldShouldReturn to get the keyboard to dismiss:
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
TextFieldDidEndEditing will then be called as well, but you need to resignFirstResponder before that happens.
I found out what the problem was (but not why...); I was using
[controller initGUI:self.view];
changing that to:
[controller initGUI:self.window.rootViewController.view];
makes it work. I don't know why.
For people who are interesting to do this same thing (like I said; I couldn't find even one example on the web), here is the simplified project; https://dl.dropboxusercontent.com/u/6134596/TestDelegate.zip

Implement setText:(NSString*)text method in subclassed UITextField

I'm subclassing UITextField and need a way to run some code whenever the text in the field changes, how can I do this?
(Writing the logic inside this class would let me write cleaner code outside it... I mean that I can do what I'm asking you using the UITextFieldDelegate, but I can access it only from outside the class.)
I came across the same use case of needing a custom clear button. I tried subclassing UITextField hoping that I could override setText: but that turned out to be a dead end as it isn't called every time a characters is typed or deleted as I hoped. I came up with the following solution:
- (void)awakeFromNib {
[super awakeFromNib];
self.clearButtonMode = UITextFieldViewModeNever;
UIButton *clearButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
[clearButton setTitle:#"x" forState:UIControlStateNormal];
[clearButton addTarget:self action:#selector(clearText:) forControlEvents:UIControlEventTouchDown];
self.rightView = clearButton;
[self addTarget:self action:#selector(textChanged:) forControlEvents:UIControlEventEditingChanged];
}
- (void)textChanged:(UITextField *)sender {
self.rightViewMode = sender.text.length > 0 ? UITextFieldViewModeWhileEditing : UITextFieldViewModeNever;
}
- (void)clearText:(UIButton *)sender {
self.text = #"";
[self textChanged:self];
}
Using the UIControlEventEditingChanged we can react to changes in text brought about by the keyboard but not by setting the text in code. Since I also want to respond to text brought about by the clearText: method I have to call the textChanged: method manually following the clear. If the text is set in code elsewhere there would be a need to call textChanged to compensate.
In .h file of your viewcontroller just define this deledate
#interface yourviewcontroller <UITextFieldDelegate>
After that in .m file use bellow code..
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
.....Do Somthing Here....
}
this is delegate method when textfield text changed this method called everytime
.
How is the code cleaner outside of it by not using the UITextFieldDelegate method? You're kind of breaking the MVC design paradigm by trying to tell a view class (your UITextField) how to respond to changes, which is what a controller is meant to do. Could you give a little more insight into why you think it's cleaner to override setText as opposed to handling things in your delegate implementation?

how do I tell which UITextField just triggered the textFieldShouldReturn callback?

I have mulitple UITextFields in a view.
I'm assuming the place to capture the vlue of a UITextField once the user comes out of it is to implement the delegate method "textFieldShouldReturn".
Question - In "textFieldShouldReturn" however, how do I tell which of the UITextField's triggered this?
For example assuming at this stage I now need to update my data model with the value of what the UITextField now shows, so need to update the correct field in the model with aligns with that particular UITextField.
PS If there's a better approach, or a way to kind of "binding" approach I'm missing I'd be interested
...or you can skip all the tags and make your UITextViews instance vars and do:
- (void)viewDidLoad {
myTextView1 = [[UITextView alloc] init];
myTextView2 = [[UITextView alloc] init];
myTextView3 = [[UITextView alloc] init];
myTextView4 = [[UITextView alloc] init];
......
}
- (void)textFieldShouldReturn:(UITextField *)textField {
BOOL shouldReturn = NO;
if (textField == myTextView1)
{
shouldReturn = YES;
}
...and so on...
}
... release the instance vars in the dealloc...
I kinda prefer this way, but the other answer will work too.

EXC_BAD_ACCESS when using resignFirstResponder on textFieldShouldReturn for iphone

I have a textfield that i want to hide when the user presses the return button. the textfield was created in the interface builder, i added the textfield delegate in my .h file, and set the delegate for the textfield as the file owner.
#interface ProfileEdit : UIViewController<UITextFieldDelegate>{
UITextField *textfield1;
UITextField *textfield2;
UITextField *textfield3;
}
- (void)viewDidLoad
{
textfield1 = [[UITextField alloc] initWithFrame:CGRectMake(20, 49, 164, 31)];
[textfield1 setDelegate:self];
[textfield1 setAutocorrectionType:UITextAutocorrectionTypeNo];
[self.view addSubview:textfield1];
textfield2 = [[UITextField alloc] initWithFrame:CGRectMake(20, 124, 164, 31)];
[textfield2 setDelegate:self];
[textfield2 setAutocorrectionType:UITextAutocorrectionTypeNo];
[self.view addSubview:textfield2]
textfield3 = [[UITextField alloc] initWithFrame:CGRectMake(20, 198, 164, 31)];
[textfield3 setDelegate:self];
[textfield3 setAutocorrectionType:UITextAutocorrectionTypeNo];
[self.view addSubview:textfield3];
[super viewDidLoad];
}
I also put a button in the background, where the touchupinside event triggers
-(IBAction)hideKeyboard:(id)sender{
[textfield1 resignFirstResponder];
[textfield2 resignFirstResponder];
[textfield3 resignFirstResponder];
}
This works fine, no errors. But for this
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[self hideKeyboard:nil];
return YES;
}
I get the EXC_BAD_ACCESS in the main.m. I've been stuck on this for a couple days and have no idea why this is happening.
I tested this on my iphone and there was no error. I think it has to do with the simulator itself. I found that if i put a delay on the [testField resignFirstResponder], no error is thrown in the simulator
For any EXC_BAD_ACCESS errors, you are usually trying to send a message to a released object. The BEST way to track these down is use NSZombieEnabled.
This works by never actually releasing an object, but by wrapping it up as a "zombie" and setting a flag inside it that says it normally would have been released. This way, if you try to access it again, it still know what it was before you made the error, and with this little bit of information, you can usually backtrack to see what the issue was.
It especially helps in background threads when the Debugger sometimes craps out on any useful information.
VERY IMPORTANT TO NOTE however, is that you need to 100% make sure this is only in your debug code and not your distribution code. Because nothing is ever released, your app will leak and leak and leak. To remind me to do this, I put this log in my appdelegate:
if (getenv("NSZombieEnabled"))
NSLog(#"NSZombieEnabled enabled!");
If you need help finding the exact line, Do a Build-and-Debug (CMD-Y) instead of a Build-and-Run (CMD-R). When the app crashes, the debugger will show you exactly which line and in combination with NSZombieEnabled, you should be able to find out exactly why.
Change return value of textFieldShouldReturn to NO.
I had this problem even without resignFirstResponder call when I was displaying a view controller.
You should re-write the hideKeyboard method to:
- (IBAction)hideKeyboard:(id)sender; {
if ([textfield1 isFirstResponder]) {
[textfield1 resignFirstResponder];
}
if ([textfield2 isFirstResponder]) {
[textfield2 resignFirstResponder];
}
if ([textfield3 isFirstResponder]) {
[textfield3 resignFirstResponder];
}
}
Also, make sure that the outlets are all hooked up properly in the nib, and that your file is a UITextFieldDelegate, and the textfields should have their delegate hooked up to file owner in the nib. That should (hopefully) fix the problem.
EDIT: You should try putting the 3 UITextFields in the nib, and hooking them up that way. It usually results in less problems, and it is easier to change the design later if you need to.
Hope that helps!