iPhone UItextfield entry saving method - iphone

Just ran into UX problem to save UITextField input value.I've got 6 UItextfield entries which saves individual value in sqlite db.
Right now each field has separate save button.So six ones quite look messy and silly.
I just want to know if there is any method to save entry after editing ends.
To be more concise...
I want to save data in UITextField after user ends editing.Just needs 'Saving Logic' for problem

You probably want to use an object which implements UITextFieldDelegate protocol. It defines –textFieldShouldEndEditing: and –textFieldDidEndEditing: methods which are called just before and once text editing ends.
Your delegate should be declared like:
#interface ATextFieldDelegate : NSObject<UITextFieldDelegate>
{
}
#end
And implements the methods:
#implementation ATextFieldDelegate
- (BOOL) textFieldShouldBeginEditing:(UITextField *)textField
{
// Test if the textField.text is valid for storage
// Return YES if it is, NO if not
}
- (void) textFieldDidEndEditing:(UITextField *)textField
{
// Store textField.text into your SQLite database
}
#end
And you should set your UITextField's delegate:
UITextField *myTextField; // could be an IBOutlet
ATextFieldDelegate *myTextFieldDelegate; // must be initialized somewhere
myTextField.delegate = myTextFieldDelegate;

Related

UItextView delegate not called using custom keyboard

I have several UITextView subviews, all using the same custom input interface (basically a numberpad with an autofill-option and a save button).
My problem is that the delegate method shouldChangeCharactersInRange: is not called when the textfield's text is modified from my custom keyboard (it does work when pasting text from clipboard into the textfields and also when using the standard numberpad keyboard). The text of the textfields change, but the delegate method to prevent invalid entries is not called. Other delegate methods of style DidBeginEditing: are called always.
despite of what is said in this SO LINK the documentation states that the shouldChangeCharactersInRange: delegate method will be called: "The text view calls this method whenever the user types a new character or deletes an existing character."
What am I missing?
relevant code parts:
ViewController.h:
#interface ManualPositionViewController : UIViewController <UITextFieldDelegate> {
LocationEntryTextField *latitude;
}
#property (nonatomic, retain) IBOutlet LocationEntryTextField *latitude;
#property (nonatomic, retain) IBOutlet LocationKeyboard *locationKeyboard;
..
ViewController.m:
#synthesize latitude;
#synthesize locationKeyboard;
self.latitude.inputView = locationKeyboard;
self.latitude.delegate = self;
- (void)textFieldDidBeginEditing:(LocationEntryTextField *)aTextField {
NSLog(#"textFieldDidBeginEditing called!");
self.locationKeyboard.currentTextfield = aTextField;
}
- (BOOL)textField:(LocationEntryTextField *)editedTextField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)replacementString {
NSLog(#"shouldChangeCharactersInRange called!");
NSCharacterSet *decimalSet = [NSCharacterSet decimalDigitCharacterSet];
if ([[replacementString stringByTrimmingCharactersInSet:decimalSet] isEqualToString:#""]) {
NSLog(#"Result: YES");
return YES;
}
else {
NSLog(#"Result: NO");
return NO;
}
}
LocationKeyboard.h:
#import <UIKit/UIKit.h>
#import "LocationEntryTextField.h"
#interface LocationKeyboard : UIView {
LocationEntryTextField *currentTextfield; // track first responder
}
#property (weak) LocationEntryTextField *currentTextfield;
- (IBAction) numberButtonPressed:(UIButton*)sender;
- (IBAction) backspaceButtonPressed:(UIButton*)sender;
#end
- (IBAction) numberButtonPressed:(UIButton*)sender {
NSString *entryString = #"test";
[self.currentTextfield replaceRange:self.currentTextfield.selectedTextRange withText:entryString];
}
LocationEntryTextField.h:
#interface LocationEntryTextField : UITextField
..
This line:
[self.currentTextfield replaceRange:self.currentTextfield.selectedTextRange withText:entryString];
doesn't result in a call to textField:shouldChangeCharactersInRange:replacementString:. Is that what you are expecting?
Since you are explicitly changing the text of the text field, there is no "typing" going on.
The proper way to have your custom keyboard update the text field is to call the 'insertText:` method. This method will properly deal with any selection, moving the cursor, and calling delegate methods.
Edit: You may wish to look at my answer here for a complete custom keyboard setup (minus the actual buttons).

UITextField in UITableViewCell and validation in modal view

I am using the approach described in this stackoverflow posting to retrieve values from a textfield. My problem is that the tableview is presented modally and I have a save button that validates the input and stores it.
The problem is that the textFieldDidEndEditing method is not called when the user clicks an UIBarButtonItem (= the save button, which closes the modal view).
In this event (when the user wants to save the input) I would like to validate it. But the values are stored in properties in the textFieldDidEndEditing. Due to the fact that this method is not called, I cannot validate the input values correctly.
Does anyone have a hint or solution on this?
Thanks in advance!
You should assign unique tag numbers to your text fields, then keep track on which is currently active (i.e. use a int iVar to store the active text fields tag value) in the textFieldDidBeginEditing delegate and when the user clicks the save, you should get the last textfield by it's tag value and then it's text value so you can validate it.
Okay, here we go:
Thanks to #Lefteris and his idea with storing the current index. Due to the fact that I cannot store the index into the tag attribute I decided to store the active indexPath and additionally the active textField. (I know, a reference to the UITextField would have been enough but I needed it for other stuff)
First I have added these two properties:
#property (nonatomic, strong) NSIndexPath *activeIndexPath;
#property (nonatomic, strong) UITextField *activeTextField;
Then I implemented textFieldDidBeginEditing: and textFieldDidEndEditing: of UITextFieldDelegate.
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
NSIndexPath *indexPath = (NSIndexPath*)[self.tableView indexPathForCell:(UITableViewCell*)[[textField superview] superview]];
self.activeTextField = textField;
self.activeIndexPath = indexPath;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
NSString *input = textField.text;
//assuming values from input textfield into corresponding properties
[self assumeInput:input withIndexPath:self.activeIndexPath];
self.activeTextField = nil;
self.activeTextField = nil;
}
In textFieldDidEndEditing: I am storing the values into my properties (such as self.firstName, self.lastName, and so on...) by using the method [self assumeInput:input withIndexPath:self.activeIndexPath];.
In my saveAction-Method I am storing the value from the currently active TextField.
- (IBAction)saveButtonClicked:(UIBarButtonItem *)sender
{
//assuming input from active field (didEndEditing _not_ called right now!)
[self assumeInput:self.activeTextField.text withIndexPath:self.activeIndexPath];
//test output
NSLog(#"firstName: %#", self.firstName);
NSLog(#"lastName: %#", self.lastName);
NSLog(#"email: %#", self.email);
...
}
... and that's it!
Hope it helps! Thanks to #Lefteris for his input.
Best,
Chris

UITextField crashes if changing text in editing changed

I wrote a simple ios5 application (includes garbage collector) that has a single view and a UITextField
I need to analyze input text in this UITextField
here's my code.
header file:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITextFieldDelegate>
{
IBOutlet UITextField *myTextField;
}
#property (nonatomic, retain) IBOutlet UITextField *myTextField;
-(IBAction)editingChanged:(UITextField *)sender;
editingChanged: tracked with send event editing changed so this method calls everytime user changes something in my UITextField
part of implementation file:
#pragma mark - textField
-(NSString *)stringWithoutAbc:(NSString *)sourceString
{
NSString *resultString=[sourceString stringByReplacingOccurrencesOfString:#"abc:" withString:#""];
if (![resultString isEqualToString:sourceString])
{
NSLog(#" sourceString: %#", sourceString);
NSLog(#" resultString: %#", resultString);
};
return resultString;
}
-(IBAction)editingChanged:(UITextField *)sender
{
NSLog(#"editing Changed. text: %#", sender.text);
//removing "abc:" from string in text field
NSString *str=[self stringWithoutAbc:sender.text];
//if something was removed - changing text in text field
if (![str isEqualToString:sender.text])
{
sender.text=str;
};
}
Everytime user changes text in UITextField we remove "abc:" strings from this text using standard NSString method.
The problem is: the application is unstable. It sometimes crashes when "abc:" gets removed.
Help me please. How to solve this problem?
You can use below textField's delegate method :-
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
If you are using Arc, you don't have to retain the object. And btw, ARC is not garbage collector.
http://longweekendmobile.com/2011/09/07/objc-automatic-reference-counting-in-xcode-explained/
MAybe because you use retain on the textField.

How can I dismiss the keyboard programmatically?

I need a way of determining the UITextField that is currently selected in a view. Is this possible without passing a reference or tag?
To be more specific I need to be able to tell which UITextField is selected so that I can hide the keyboard. The reason I need this is because I want to create a UIToolbar to add to all the UITextField's as an input accessory. On this UIToolbar I will add a 'Done' button, when pressed this should hide the keyboard for the currently selected UITextField.
I assume you mean you want to know which UITextField is the first responder (which is the text field that gets input from the keyboard).
There is no public API for this (though there is a private API). You can track which text field is the first responder manually using the textFieldDidBeginEditing: method of each text field's delegate, or you can use a little trickery to find the first responder at any time.
Here's the trick. The UIApplication object knows which object is the first responder, and can send a message to it. So you write a category like this on UIResponder:
UIResponder+firstResponderHack.h
#import <UIKit/UIKit.h>
#interface UIResponder (firstResponderHack)
+ (UIResponder *)firstResponderByHack;
#end
UIResponder+firstResponderHack.m
#import "UIResponder+firstResponderHack.h"
#interface FirstResponderFinder : NSObject
#property (strong, nonatomic) UIResponder *firstResponder;
#end
#implementation FirstResponderFinder
#synthesize firstResponder = _firstResponder;
#end
#implementation UIResponder (firstResponderHack)
- (void)putFirstResponderIntoFinder:(FirstResponderFinder *)finder {
if (self.isFirstResponder)
finder.firstResponder = self;
}
+ (UIResponder *)firstResponderByHack {
FirstResponderFinder *finder = [FirstResponderFinder new];
// Sending an action to nil sends it to the first responder.
[[UIApplication sharedApplication] sendAction:#selector(putFirstResponderIntoFinder:) to:nil from:finder forEvent:nil];
return finder.firstResponder;
}
#end
Then you can find the first responder, and check whether it's a UITextField, like this:
UIResponder *firstResponder = [UIResponder firstResponderByHack];
if (firstResponder && [firstResponder isKindOfClass:[UITextField class]]) {
UITextField *textField = (UITextField *)firstResponder;
// do something with textField
}
There is an easy way to dismiss the keyboard without having to track the currently active control, or iterating through all the available controls, or using a UITextFieldDelegate.
[self.view endEditing:YES]
From the docs:
endEditing:
Causes the view (or one of its embedded text fields) to
resign the first responder status.
- (BOOL)endEditing:(BOOL)force
Parameters
force
Specify YES to force the first responder to resign, regardless of whether it wants to do
so.
Return Value
YES if the view resigned the first responder status or NO if it did not.
Discussion
This method looks at the current view and its subview
hierarchy for the text field that is currently the first responder. If
it finds one, it asks that text field to resign as first responder. If
the force parameter is set to YES, the text field is never even asked;
it is forced to resign.
There is a delegate method:
- (void)textFieldDidBeginEditing:(UITextField *)textField
Apple Docs:
This method notifies the delegate that the specified text field just
became the first responder. You can use this method to update your
delegate’s state information. For example, you might use this method
to show overlay views that should be visible while editing.
There is also a property:
#property(nonatomic, readonly, getter=isEditing) BOOL editing
Apple Docs:
A Boolean value indicating whether the text field is currently in edit
mode. (read-only)
Just make an ivar for the UITextView in your header file:
UITextField *editingField;
#property (nonatomic, copy) UITextField *editingField;
Then,
- (void)textFieldDidBeginEditing:(UITextField *)textField;
{
editingField = textField;
// Whatever else you want to do
}
I'm thinking that you need to diff the textFields without reference.
So, the recommended why is using ObjectiveC runtime.
It's pretty straight forward.
Firstly:
#import <objc/runtime.h>
Then, define a char for its address:
static char UITextFieldViewIdentifier;
Then set the identifier with something like this:
objc_setValue(textField, &UITextFieldViewIdentifier, #"Identifier") //typing on a phone, not so sure about the expression
In the delegate method:
NSString *identifier = objc_getObject(textField, &UITextFieldViewIdentifier)
Just call this line where you want to dismiss the keyboard:
[self.view endEditing:YES];

How to add a method to UITextField & UITextView?

I want to put something like this in a method for UITextField & UITextView.
- (void)changeKeyboardType:(UIKeyboardType)keyboardType {
paymentTextView.keyboardType = UIKeyboardTypeAlphabet;
[paymentTextView resignFirstResponder];
[paymentTextView becomeFirstResponder];
}
How do I do this? I know I can create categories for both UITextField & UITextView but is it possible to do it in one shot?
By one shot, I mean add it to both classes with one protocol instead of making two categories, one for UITextView & one for UITextField. I've heard a protocol is similar to a Ruby module, but in a Ruby module, I can implement the method. In a protocol, it only seems that I can declare the method but not implement it. Can I also implement the method in the protocol, and then include this protocol in UITextField & UITextView?
How to add a method to an existing protocol in Cocoa? is close but not quite.
What about something like this?
// UIView+UITextInputTraits.h
#interface UIView (UITextInputTraits)
- (void)changeKeyboardType:(UIKeyboardType)keyboardType;
#end
// UIView+Additions.m
#import "UIView+UITextInputTraits.h"
#implementation UIView (UITextInputTraits)
- (void)changeKeyboardType:(UIKeyboardType)keyboardType {
if ([self conformsToProtocol:#protocol(UITextInputTraits)]) {
id<UITextInputTraits> textInput = (id<UITextInputTraits>)self;
if (textInput.keyboardType != keyboardType) {
[self resignFirstResponder];
textInput.keyboardType = keyboardType;
[self becomeFirstResponder];
}
}
}
#end
For each of these, you can create a category.
Interface file:
#interface UITextField (ChangeKeyboard)
- (void)changeKeyboardType:(UIKeyboardType)keyboardType;
#end
Implementation file:
#implementation UITextField (ChangeKeyboard)
- (void)changeKeyboardType:(UIKeyboardType)keyboardType {
self.keyboardType = keyboardType;
[self resignFirstResponder];
[self becomeFirstResponder];
}
#end
That would be the way to add these, but I haven't tested the functionality.
Like #Josh said, method swizzling isn't what you are looking for. However what I actually had in mind (My bad for not researching more into it before submitting an answer) is to add method at runtime on UITextView and UITextField. While this needs a bit more code to implement, it can give you the sort of one-shot you are looking for (You create a method and add it to both UITextView & UITextField at run-time)
Here's a blog post about it:
http://theocacao.com/document.page/327
http://www.mikeash.com/pyblog/friday-qa-2010-11-6-creating-classes-at-runtime-in-objective-c.html