Prompting and Delegate question - objective-c

I have a class that needs to ask the user a question and wait for the users response to determine the next action. What would be the best way to do this? Using a delegate? How? I have a UITextField and a UITextField in the class.
Thanks

It all depends upon how you wish for the user to submit the data. The most user friendly way is to do as TahoeWolverine explained and implement - (BOOL)textFieldShouldReturn:(UITextField *)textField from UITextFieldDelegate. In order to use this, the class that implements textFieldShouldReturn: must have <UITextFieldDelegate> protocol in its interface declaration; moreover, the textfield in question must have the UITextFieldDelegate-implementing class set as its delegate. In most cases those would look like this:
#interface SomeViewController : UIViewController <UITextFieldDelegate> {
UITextField *myField;
}
#property (nonatomic, retain) IBOutlet UITextField *myfield
#end
and somewhere in the implementation:
[[self myField] setDelegate:self];
Finally, implementing the UITextFieldDelegate protocol:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if (textField == [self myField]) {
[self doSomethingWithText:[[self myField] text]];
}
}
Hope that helps.

Yes, you should use a delegate, and link that to the keyboard's done button (I'm assuming that you're presenting the user a keyboard). Simply link your delegate to the return key of the keyboard, and that should do the trick.

Related

Getting Key down event in an NSView controller

I'm trying to find a solution that allows me to get keydown events in a view controller.
I do not believe a view controller is part of the responder chain by default.
I would appreciate a sample of how to go about this. I have had trouble finding documentation I can understand on how to add the VC to the responder chain and get the events.
Thanks.
Miek
You can implement something like this:
-(void) globalKeyDown: (NSNotification *) notification
method in your controller class, and then just add the observer in awakeFromNib...or loadView method of your controller
- (void)awakeFromNib
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(globalKeyDown:)
name:#"my_keyEvent"
object:nil];
}
in your view class
-(void)keyDown:(NSEvent *)theEvent
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"my_keyEvent"
object:theEvent
userInfo:#{#"sender":self}];
}
NSViewController doesn't have a default way to do this. However, you can achieve this through subclassing NSView. Here is the basic idea:
If you create a view subclass, you can set your view controller as a delegate and create a delegate method that handles events.
You can declare a delegate protocol at the start of your view header.
Import your view header in the view controller header. Declare the view controller as implementing the protocol.
In your view keyDown send the event to the delegate.
Another way is to post NSNotifications in your keyDown and observe and handle the notifications in your view controller. Other ways also exist.
NSView Subclass with Delegate method explained
Here is the delegation example with an NSView subclass which declares a protocol in its header with one required method, an IBOutlet id property that conforms to the protocol. The NSView subclass calls this method to its delegate whenever it wants to. If the delegate is nil, that's fine in Cocoa. Also note, tangentially, I have added IB_Designable and IBInspectable to the view's color properties. This allows setting them in IB and requires the 10.10 SDK.
The app delegate has imported the NSView subclass in the AppDelegate.m implementation file and adopted the protocol in the AppDelegate class extension at the top of the .m file. In the #implementation section it also implements the method.
Also note in IB, I added an NSView to the window, then set its class to the custom NSView subclass in the inspector. Finally, I set its eventDelegate IBOutlet to the AppDelegate proxy in IB.
Custom NSView subclass interface
#import <Cocoa/Cocoa.h>
#protocol EventDelegatingViewDelegate <NSObject>
- (void)view:(NSView *)aView didHandleEvent:(NSEvent *)anEvent;
#end
IB_DESIGNABLE
#interface EventDelegatingView : NSView
#property IBOutlet id<EventDelegatingViewDelegate> eventDelegate;
#property IBInspectable NSColor *fillColor;
#property IBInspectable NSColor *strokeColor;
#end
Custom NSView subclass implementation
#import "EventDelegatingView.h"
#implementation EventDelegatingView
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent {return YES;}
// The following two methods allow a view to accept key input events. (literally they say, YES, please send me those events if I'm the center of attention.)
- (BOOL)acceptsFirstResponder {return YES;}
- (BOOL)canBecomeKeyView {return YES;}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
[self.fillColor set];
NSRectFill(self.bounds);
[self.strokeColor set];
NSFrameRect(self.bounds);
}
// Notice these don't do anything but call the eventDelegate. I could do whatever here, but I didn't.
// The NICE thing about delgation is, the originating object stays in control of it sends to its delegate.
// However, true to the meaning of the word 'delegate', once you pass something to the delegate, you have delegated some decision making power to that delegate object and no longer have any control (if you did, you might have a bad code smell in terms of the delegation design pattern.)
- (void)mouseDown:(NSEvent *)theEvent
{
[self.eventDelegate view:self didHandleEvent:theEvent];
}
- (void)keyDown:(NSEvent *)theEvent
{
[self.eventDelegate view:self didHandleEvent:theEvent];
}
#end
App Delegate (and eventDelegate!) implementation
#import "AppDelegate.h"
// Import the view class and if there were other files that implement any protocol
#import "EventDelegatingView.h"
// Declare protocol conformance (or more accurately, not only import that protocol interface, but say you're going to implement it so the compiler can nag you if you don't)
#interface AppDelegate ()<EventDelegatingViewDelegate>
#property (weak) IBOutlet NSWindow *window;
// For the simplest demo app we don't even need this property.
#property IBOutlet EventDelegatingView *eventDelegatingView;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
// It's all right here. Receive a reference to a view and a reference to an event, then do as you like with them.
#pragma mark - EventDelegatingViewDelegate
- (void)view:(NSView *)aView didHandleEvent:(NSEvent *)anEvent
{
NSString *interestingEventNote;
switch (anEvent.type) {
case NSKeyDown:
case NSKeyUp:
{
// For simplicity we won't try to figure out the modifier keys here.
interestingEventNote = [NSString stringWithFormat:#"%# key was pressed.", anEvent.charactersIgnoringModifiers];
}
break;
case NSLeftMouseDown:
{
interestingEventNote = [NSString stringWithFormat:#"Left mouse down at point %# in window", NSStringFromPoint(anEvent.locationInWindow)];
}
break;
default:
break;
}
NSLog(#"%# %# aView=%#\n note=%#", self, NSStringFromSelector(_cmd), aView, interestingEventNote?interestingEventNote:#"Nothing worth noting");
}
#end
And that's it for the power of delegation. Basically it's callbacks of sorts and is a great way to build a class to enable it to defer something elsewhere as wanted. Moving some business logic to the right place in a fairly lazy and open and loosely coupled way.
NOTE: My code example shows using the app delegate. But the principal is the same. A view controller is little more than a delegate and you can add as much or as little as you like.
In your NSWidow (or NSWindowController) class implementation set your view controller as the first responder:
[self makeFirstResponder:yourViewControllerInstance];
You must, of course, make your NSViewController class return YES to the acceptsFirstResponder message.

textFieldShouldReturn is not called

I want to make the keyboard disappear when the user clicks the "return" button, I was told to use
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
[tf resignFirstResponder];
return YES;
}
But nothing happens when I click the "return" button, the method isn't even being called. I am doing this in
#interface gameOverMenu : UIView
not in the ViewController. I also don't use interface builder. What should I do?
You need to make sure you implement the UITextFieldDelegate and set your UITextField delegate to self. In your .h file:
#interface gameOverMenu : UIView <UITextFieldDelegate>
And somewhere in your .m file (viewDidLoad: maybe):
self.yourTextField.delegate = self;
Now your -(BOOL)textFieldShouldReturn:(UITextField *)textField method should be called.
Make sure that you have set the parent class (whatever it is) as a UITextFieldDelegate

UITextField and #property id<UITextFieldDelegate>

I have UITextField and I have
#property (nonatomic, assign) id <UITextFieldDelegate> delegate;
After pressing a done button on keybord, it should dismiss. Can someone tell how I can do it using this property?
The dismissing of the keyboard does not happen merely by being a delegate of the UITextField. Your delegate must dismiss it.
In the viewDidLoad in your controller you must assign the delegate, or set it up in Interface Builder:
- (void)viewDidLoad {
self.textField.delegate = self;
}
Then in your controller, implement the following delegate method.
#pragma mark - UITextFieldDelegate
// This method gets called when you hit the enter key on the keyboard,
// or in this case 'DONE'. The textfield is asking if it should put
// a carriage return in the field. This is our opportunity to dismiss
// the keyboard.
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder]; // This is what hides the keyboard
return NO;
}
Further reading:
Responder Chain - developer.apple.com
UITextFieldDelegate Protocol Reference - developer.apple.com
Link didEndOnExit to a method that has [self resignFirstResponder]

UITextFieldDelegate SecondView

I'm using iOS 5 and trying to use TextField with UITextFieldDelegate, it's worked exactly like I want (but JUST in the first View). I don't understand, why it's not working in the next view.
For simple example, I created new project (ViewController). There I added one button, that connect to another view (SecondViewController). In the SecondViewController, I have one TextField. With this textField I want to use textFieldShouldReturn. But it seems, that this method is not being called. What I know, I should write the delegate in ViewDidLoad. Should I write myTextField.delegate = self; ? but I think something wrong there. I used Debugging, and always at that position, i'm getting problem. Could you please tell me, what the problem is? and how can i solve it ;(
Thanks in advance.....
Here is my code (that it works, in the first view (ViewController). Unfortunately here not (SecondViewController):
SecondViewController.h
#interface SecondViewController : UIViewController<UITextFieldDelegate>
#property (strong, nonatomic) IBOutlet UITextField *myTextField;
#end
SecondViewController.m
#implementation SecondViewController
#synthesize myTextField;
- (void)viewDidLoad{
[super viewDidLoad];
myTextField.delegate = self; // here i get the problem
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{ // this method is not being called
[textField resignFirstResponder];
NSLog(#"is called!");
NSString *valueMyTextField = myTextField.text;
NSLog(#"%#", valueMyTextField);
return YES;
}
Problem solved... :)
The problem was the connection from firstView to secondView.
Do not use addSubView, if you want to add Controller!
Use presentModalViewController :)
Hope it helps, in case you have the same problem like me.
In the nib file, please check that whether you have checked the Auto-enable Return Key check box for the text field.

UIButton set touch handler in code

I want to accomplish touching a UIButton and having code run in a different class than the owner.
I realize I can do a touchUpInside to the button's owner (ClassA) and then call the method inside ClassB that I want called, but is there any way to expedite this?
ideas:
have ClassB be the delegate for the ClassA->UIButton
set the touchUpInside call in programming to used the function inside ClassB
I'm not sure how to accomplish either of these ideas :( Input is mas appreciated!
One option is to set the button up using
[myButton addTarget:yourOtherClass action:#selector(mySelector:) forControlEvents:UIControlEventTouchUpInside];
but this is a bit dangerous because target is not retained so you could send the message to a deallocated object.
You could instead set up a protocol
MyController.h
#protocol MyControllerDelegate
- (void)myController:(MyController *)controller buttonTapped:(UIButton *)button;
#end
#interface MyController : UIViewController
#property (nonatomic, assign) id <MyControllerDelegate> delegate;
- (IBAction)buttonTapped:(UIButton *)button;
#end
Then in your implementation
MyController.m
- (IBAction)buttonTapped:(UIButton *)button
{
if ([self.delegate respondsToSelector:#selector(myController:buttonTapped:)]) {
[self.delegate myController:self buttonTapped:button];
}
}
As the method defined in the protocol was not optional I could have instead done a check for (self.delegate) to make sure it is set instead of respondsToSelector.