How to discover each UI object sent the message - objective-c

I am still learning Objective C/Cocoa and I am building a program with a simples interface. In this interface, there are some NSTextField which has this delegate:
- (void) controlTextDidChange: (NSNotification *) obj{
//Some code here
}
When the user changes the the text of any of these NSTextField the program needs to check if the number inside the NSTextField is an integer. If the provided string is not an Integer I want to display a dialog with the error and each NSTexField the error occurred, since I have more than one NSTextField connected to this method.
My question is: how can I discover each UI object sent the message to the controlTextDidChange method?
Thanks in advance.

- (void)controlTextDidChange:(NSNotification *)anotif
{
if ([anotif object]==field1)
{
// field1 processing
}
else
{
// field2 processing
}
}
From
controlTextDidChange with 2 nstextfields - call different selectors

If you don't have the UITextField subviews as properties, you can set tag for every UITextField subview change the code #Bruno provided as follows:
- (void)controlTextDidChange:(NSNotification *)anotif
{
UITextField *textField = (UITextField *)[anotif object];
if (textField.tag == 1)
{
// field1 processing
}
else
{
// field2 processing
}
}

Related

How to fill a text field in a collectionview cell after returning from popover

Can anyone please help me... I have a collection view that displays data retrieved from a SQLite database. Certain text fields in the collection view cells need to be updated using a pre-defined list in a pop-over.
The popover displays the right values, and I do retrieve the selected value but I cannot manage to update the text field in the collectionview with the value. I assume that I need to specify the cell that contains the text field using the indexpath upon starting the segue, but I do not know how.
I start the popover using this:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
if (textField.tag == 101) {
Global.Table = #"Access";
Global.Code = #"G";
Global.Request = #"Access";
[self performSegueWithIdentifier:#"PopUp" sender:self];
return NO;
}
else {
return YES;
}
}
The popover sends a notification after selecting the correct value in a tableview and gets dismissed.
- (void)receivedNotification:(NSNotification *) notification {
if ([[notification name] isEqualToString:#"scroller"]) {
if ([Global.Request isEqualToString:#"Access"]) {
NSLog(#"Returnvalue is %#",Global.Value);
//this is where the problem arises, I cannot access the text field to update the value, the return value is correct.
[self.collectionviewManagement selectItemAtIndexPath:0 animated:NO scrollPosition:0];
WDSCellManagement *cell = [_collectionviewManagement dequeueReusableCellWithReuseIdentifier:#"CellManagement" forIndexPath:0];
cell.AccessPersons.text = Global.Value;
}
}
}
Thanks a lot for your help!
You use a delegation pattern, as with any view controller interaction:
YourPopupController.h:
#import <UIKit/UIKit.h>
#class YourPopViewController;
#protocol YourPopupViewControllerDelegate <NSObject>
#optional
- (void)yourPopupViewController:(YourPopViewController *)yourPopupViewController
returnedValue:(NSString *)value;
#end
#interface YourPopupViewController : UITableViewController
#property (weak, nonatomic) id<YourPopupViewControllerDelegate> delegate;
#end
YourPopupViewController.m:
- (void)receivedNotification:(NSNotification *) notification {
if ([[notification name] isEqualToString:#"scroller"]) {
if ([Global.Request isEqualToString:#"Access"]) {
if ([_delegate respondsToSelector:#selector(yourPopupViewController:returnedValue:)]) {
[_delegate yourPopupViewController:self
returnedValue:Global.Value];
}
}
}
}
You then conform to the YourPopupViewControllerDelegate protocol in your presenting view controller and update the collection view when the delegate method is called, dismissing the popup view controller.

How to properly use delegation for NSTextField

Im trying to implement a delegate for a NSTextField object so I can detect the user input in real time and give some feedback about no allowed input in that particular field.
Especially, I want to simulate the onChange() method from JavaScript, detecting the user input in real time and show him a warning if it is writing a non supported value.
i.e. The app have a text field it only accept numeric values from 0 to 255 (like RGB values) and I want to know when the user is writing not numeric values or out of range values to instantly show him a warning message or change the text field background color, just a visual hint to let him know the input it's wrong.
Like you see on the pictures above, I want to show a warning sign every time the user inputs a forbidden value in the text field.
I have been reading a lot of the Apple's documentation but I don't understand which delegate to implement (NSTextFieldDelegate, NSTextDelegate, or NSTextViewDelegate), also, I have no idea how to implement it in my AppDelegate.m file and which method use and how to get the notification of user editing.
Right now, I already set the Delegate in my init method with something like this [self.textField setDelegate:self]; but I don't understand how to use it or which method implements.
I found a solution using the information posted in this question... Listen to a value change of my text field
First of all I have to declare the NSTextFieldDelegate in the AppDelegate.h file
#interface AppDelegate : NSObject <NSApplicationDelegate, NSTextFieldDelegate>
After that, I have to instantiate the delegate for the NSTextField object I want to modify while the user update it in the AppDelegate.m file.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[self.textField setDelegate:self];
}
Finally, I implement the methods to detect field editing with the changes I want to set.
- (void)controlTextDidChange:(NSNotification *)notification {
NSTextField *textField = [notification object];
if ([textField doubleValue] < 0 | [textField doubleValue] > 255) {
textField.textColor = [NSColor redColor];
}
}
- (void)controlTextDidEndEditing:(NSNotification *)notification {
NSTextField *textField = [notification object];
if ([textField resignFirstResponder]) {
textField.textColor = [NSColor blackColor];
}
}
Make your class conform to the NSTextFieldDelegate protocol. It need's to be that protocol because in the documentation it says the type of protocol the delegate conforms to.
#interface MyClass : NSObject
And implement the delegate's methods (just add them to your code). Example
- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor
{
}
EDIT:
I think in your case it would be better to replace the TextField for a TextView and use a NSTextViewDelegate, in the delegate, the method of most interst of you should be
- (BOOL)textView:(NSTextView *)aTextView shouldChangeTextInRange:(NSRange)affectedCharRange replacementString:(NSString *)replacementString
{
BOOL isValid = ... // Check here if replacementString is valid (only digits, ...)
return isValid; // If you return false, the user edition is cancelled
}

textShouldEndEditing in NSOutlineTableView is getting called twice

I just implemented following method that suppose to take some action after the value of a NSTextField is changed in my NSOutlineView
-(BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor
{
NSLog(#"end editing");
NSTextField* tf = (NSTextField*)control;
if(selectedItem && [selectedItem isKindOfClass:[HSCategoryClass class]])
{
HSCategoryClass* c = selectedItem;
c.name = tf.stringValue;
// request the update from DB
[[NSNotificationCenter defaultCenter] postNotificationName:#"updatingCategoryName"
object:c
userInfo:#{#"sender":self}];
}
return YES;
}
However, when I'm done editing and hit enter key or navigate anywhere outside of the text field this method is getting called twice instead of just once.
Does anyone know why is this?!
Any kind of help is highly appreciated!
That routine does not signify that editing has ended. Instead, it's called to find out if it should end (hence the name of the method). It can be called by the framework any number of times, and you shouldn't be relying on it for this purpose.
Instead override the NSOutlineView's textDidEndEditing: method.
Be sure to call super.
So you'd subclass the NSOutlineView and in your subclass:
- (void)textDidEndEditing:(NSNotification *)aNotification
{
// do your stuff
[super textDidEndEditing:aNotification];
}

Moving Onto The Next UITextField When 'Next' Is Tapped

I have an iPad application which has a sign up form within it. The form is very basic and contains only two UITextFields which are for Name & Email address.
The first TextField is for the candidates Name, When they enter their name in and press 'Next' on the keyboard I want this to automatically move to the next Email Address TextField to editing.
Any idea how I can set the next button the keyboard to jump to the next keyboard?
Thanks
You need to make your view controller the UITextField delegate, and implement the UITextField delegate method:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if (textField == nameField) {
[textField resignFirstResponder];
[emailField becomeFirstResponder];
} else if (textField == emailField) {
// here you can define what happens
// when user presses return on the email field
}
return YES;
}
Swift version:
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField == nameField {
textField.resignFirstResponder()
emailField.becomeFirstResponder()
} else if textField == emailField {
// here you can define what happens
// when user presses return on the email field
}
return true
}
You may also want to scroll your view for the emailField to become visible. If your view controller is an instance of UITableViewController, this should happen automatically. If not, you should read this Apple document, especially Moving Content That Is Located Under the Keyboard part.
Additionally to #lawicko 's answer I often change the button text to give that final finishing touch (e.g. says next when there are more fields and then done when on the last):
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
BOOL isLastTextField = //.. your logic to figure out if the current text field is the last
if (isLastTextField) {
textField.returnKeyType = UIReturnKeyDone;
} else {
textField.returnKeyType = UIReturnKeyNext;
}
}
Swift version of correct answer.
In my experience, you do not need to resignFirstResponder when switching textFields.
In this example, it's just your basic username and password textFields.
The keyboard "return key" in storyboard for username is set to "Next" and the one for password is set to "Done".
Then just connect the delegates for these two text fields and add this extension and you're pretty much done.
extension LoginViewController: UITextFieldDelegate {
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField == textFieldPassword {
self.view.endEditing(true)
} else {
textFieldPassword.becomeFirstResponder()
}
return true
}
}
A more consistent and robust way is to use NextResponderTextField
You can configure it totally from interface builder.
All you need to do is
Set the class type of your UITextField to be NextResponderTextField
Then set the outlet of the nextResponderField to point to the next responder it can be anything UITextField or any UIResponder subclass. It can be also a UIButton and the library is smart enough to trigger the TouchUpInside event of the button only if it's enabled.
Here is the library in action:
A Swift 4 extension. Just pass the array of UITextFields and it will connect each one to the next until the last one which resigns the first responder (hides the keyboard):
extension UITextField {
class func connectFields(fields: [UITextField]) {
guard let last = fields.last else { return }
// To reset the targets in case you call this method again to change the connected fields
fields.forEach { $0.removeTarget(nil, action: nil, for: .editingDidEndOnExit) }
for i in 0 ..< fields.count - 1 {
fields[i].returnKeyType = .next
fields[i].addTarget(fields[i + 1], action: #selector(UIResponder.becomeFirstResponder), for: .editingDidEndOnExit)
}
last.returnKeyType = .continue
last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), for: .editingDidEndOnExit)
}
}
- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
if (textField == self.textFieldName)
{
[self.textFieldName resignFirstResponder];
[self.textFieldPassword becomeFirstResponder];
}
else if (textField == self.textFieldPassword)
{
[self.textFieldPassword resignFirstResponder];
[self login:self];
}
return true;
}
#interface MLLoginViewController ()<UITextFieldDelegate>
#end
#implementation MLLoginViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.textFieldName.delegate = self;
self.textFieldPassword.delegate = self;
Make an outlet for the textfield, then
viewController.h
(IBAction)textFieldDoneEditing:(id)sender;
viewController.m
(IBAction)textFieldDoneEditing:(id)sender {
[textField resignFirstResponder];
if (textField == nameField) {
[emailField becomeFirstResponder];
}
}
Make the relation between (show the connections inspector > Sent Events)didEndOnExit and textFieldDoneEditing

UITextField editingChange Control Event not works

I have some textfields and I want to do when I change textfield1 text set text to other textfields. My code below. But it not works. How can I solve this?
- (IBAction)TCKimlikTextChange:(id)sender {
[TCKimlikText addTarget:self action:#selector(yourMethod: ) forControlEvents:UIControlEventEditingChanged];
}
-(void)yourMethod: (UITextField*)tf_{
if (tf_) {
if (TCKimlikText.text == #"1") {
AdinizText.text = #"Hacer";
}
}
}
Your code is very abstract. yourMethod, tf_ TCKimlikTextChange are all expressions that are not very human readable. You should work on your variable names.
I suppose your first method is a button handler. It just assigned a target and action to the text field, but does not call any method. You do not need that action if you use the delegate protocol.
To solve your problem: implement the UITextField delegate methods. Make sure you set the delegate (probably self) for your text fields. Your view controller must mention the <UITextFieldDelegate> protocol in its .h file. Thus, in textField:shouldChangeCharactersInRange:replacementString::
if ([textField.text isEqualToString:#"1"]) {
displayLabel.text = #"Hacer";
}
Notice that you need isEqualToString: to compare strings, a simple == won't do.
If u are want to change on the click of the return button use the delegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if(textField == field1)
[field2 setText:field1.text];
[field1 resignFirstResponder];
return YES;
}
or u can use other delegates too like:
– textFieldShouldBeginEditing:
– textFieldDidBeginEditing: