I'm running into a little issue with my textFieldDidBeginEditing method..
I'm trying to figure out which textfield is being called on to edit so I can decide if I want the view to move up or not to make the field visible.
Here is my method, I have commented some things out to try to find out where the error is:
- (void)textFieldDidBeginEditing:(UITextField *)sender
{
NSLog(#"This method is called");
//[self.view setFrame:CGRectMake(0,-120,320,568)];
if(sender.tag == _nameF.tag)
{
NSLog(#"This if is called");
//[self.view setFrame:CGRectMake(0,-120,320,568)];
}
else
{
NSLog(#"Else called instead");
}
}
I see "This method is called" in the log, so I know the method is being called in the first place, but after that, I see this:
2013-07-23 12:27:18.654 SidebarDemo[2110:60b] -[NSConcreteNotification tag]: unrecognized selector sent to instance 0x15d7b8c0
2013-07-23 12:27:18.655 SidebarDemo[2110:60b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConcreteNotification tag]: unrecognized selector sent to instance 0x15d7b8c0'
This leads me to believe that it is something with sender.tag, but I don't see anything wrong with my code, to my knowledge.
What could the issue be here? Is there another method I can use to find out what textfield is being edited?
Thanks.
Since you are setting up the UITextFieldTextDidBeginEditingNotification notification to call your textFieldDidBeginEditing: method, you need to change the method parameter. And to avoid confusion with the corresponding UITextFieldDelegate method, you should rename this method as well (which means you need to update the line of code that register the notification handler).
- (void)textFieldDidBeginEditingHandler:(NSNotification *)notification {
UITextField *textField = (UITextField *)notification.object;
// It's OK to use == here since we really do want to compare pointer values
if(textField == _nameF) {
NSLog(#"This if is called");
//[self.view setFrame:CGRectMake(0,-120,320,568)];
} else {
NSLog(#"Else called instead");
}
}
There is no need for tags since you have ivars for each text field.
BTW - why are you using notifications for this? Why not use the UITextFieldDelegate methods?
Related
I have several NSTextFields declared on my NSWindowController, all of them has as delegate the File's Owner, and respond fine to this method:
-(void)controlTextDidEndEditing:(NSNotification *)obj{
}
but I also want to know the control's value for this I used next code
-(void)controlTextDidEndEditing:(NSNotification *)obj{
if ((NSTextField *)obj == self.nombreCuentaActivoTextField) {
NSLog(#"you just edited nombreCuentaActivoTextField");
}
}
but it doesn't work, how to do that
obj is an NSNotification. You can't just cast it to an NSTextField and assume you've achieved anything useful.
The control which posted that notification and thus triggered that delegate method is the "object" of the notification. You can use [obj object] to obtain that. So, you might implement the method like so (I've renamed obj to notification for clarity):
-(void)controlTextDidEndEditing:(NSNotification *)notification{
if ([notification object] == self.nombreCuentaActivoTextField) {
NSLog(#"you just edited nombreCuentaActivoTextField");
}
}
Probably a noob question, but I cannot seem to get it right at the moment. I am working on an app where I have an Actionsheet for the confirmation of some basic things. However after the delegate is called for that Actionsheet my initial calling object is released (or not initiated).
In the delegate method I then want to call a method on that object but it just not do anything from that point.
The self.inviteSponsorsFromVC is not initiated anymore in this scenario and I want to call the saveSponsorWithEmail method from it. I cannot just reinitiate it, as the object had some objects in it, it has to use.
Everything works correctly if I just remove the actionsheet and call the saveSponsorWithEmail method directly without using a delegate.
This is my delegate method:
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
//Get the name of the current pressed button
NSString *buttonTitle = [actionSheet buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:NSLocalizedString(#"Send invitation", nil)]) {
ContactFromAddressBook *contactFromAddressBook = [self.tableData objectAtIndex:selectedIndex.row];
[self.inviteSponsorsFromVC saveSponsorWithEmail:contactFromAddressBook.email andName:contactFromAddressBook.fullName];
}
if ([buttonTitle isEqualToString:NSLocalizedString(#"Cancel", nil)]) {
NSLog(#"Cancel pressed --> Cancel ActionSheet");
}
}
My guess is that at in the delegate method the content of self.inviteSponsorsFromVC is nil. In Objective-C, when you send a message to nil the message is simply ignored (unlike C++, for instance, where you get a crash when you call a method on a NULL object).
As an experiment you can try either one of these:
If you use ARC, make the property self.inviteSponsorsFromVC a strong reference
If you don't use ARC, say [self.inviteSponsorsFromVC retain] at some point before you display the action sheet
Either way, what you need to do is to make sure that the object in self.inviteSponsorsFromVC is not deallocated before you invoke a method in it.
EDIT after your comment
The property declaration is good, it's got the strong attribute on it. In your InviteSponsorsFrom class, try to add a dealloc method and set a breakpoint there to see if the object is deallocated, and where the call comes from.
- (void) dealloc
{
[super dealloc];
}
Also make sure that an instance of InviteSponsorsFrom is created in the first place. I assume you have an initializer somewhere in that class where you can set a breakpoint and/or add an NSLog statement to make sure that the instance is created.
I am using a UIPickerView to display answers to a question. There needs to then be a button to reveal the correct answer if the user cannot work it out. I have tried the below, but the app crashes. How can i autoscroll to the correct answer?
-(void)reveal {
[myPickerView selectRow:0 inComponent:0 animated:YES];
}
EDIT: Yes i am just trying to get it to scroll to the first answer in the above example :)
[ExcerciseController reveal:]: unrecognized selector sent to instance 0x68398f0
2012-10-30 14:57:21.673 English[20786:f803] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ExcerciseController reveal:]: unrecognized selector sent to instance 0x68398f0'
* First throw call stack:
(0x1397022 0x108ccd6 0x1398cbd 0x12fded0 0x12fdcb2 0x1398e99 0x1f214e 0x1f20e6 0x298ade 0x298fa7 0x298266 0x2173c0 0x2175e6 0x1fddc4 0x1f1634 0x21a3ef5 0x136b195 0x12cfff2 0x12ce8da 0x12cdd84 0x12cdc9b 0x21a27d8 0x21a288a 0x1ef626 0x2c5d 0x2b85)
terminate called throwing an exception[Switching to process 20786 thread 0xf803]
Now, that the error/crash message is visible, it turns out that the error is not in how you call the picker's method. It is how you invoke reveal.
You call reveal with some object. Or you call it by passing a selector. However, the current selector that you are calling is reveal: but the methods name is reveal without any parameter. reveal: would require one parameter.
Wherever you call it, make sure that you call reveal and not reveal:
I assume you set the selector either in interface builder or when creating the button programmatically. That is the place where you made the mistake.
Some background:
The error message tells you what you need to know. A method name is called selector in Objective-C at runtime. In some literature you will find the wording of a message (named reveal: in your case) is sent to a receiver named ExcerciseController in your case.
Objective-C is polymorph. That means that reveal (called without any parameters) refers to another method implementation than reveal: (called with one parameter) or even reveal:: (called with three parameters).
myPickerView may not be the instance of UIPickerView as UIPickerView responds to selector - (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated
Or you have to check how the method reveal is invoked.
please try to post the crash description,Need more blocks of code to answer it :)
However just try the below code
myPickerView.delegate = self;
[myPickerView reloadAllComponents];
[myPickerView selectRow:0 inComponent:0 animated:YES];
I am getting after some time unrecognized selector sent to instance exception. When i get this i want just skip it and my app should work.
However i don't know how to catch. As this don't catch:
#property(nonatomic,retain) UIButton *button;
#try{
if(button.currentBackgroundImage == nil){//rises exception
}
}#catch(NSException *e){
}
How i could handle this ?
Thanks.
The technique I use and see often is: instead of catching the exception, check if the object responds to the selector:
if(![button respondsToSelector:#selector(currentBackgroundImage)] || button.currentBackgroundImage == nil) {
// do your thing here...
}
If you are getting this exception, it means there is a design flaw, a bug in your code. Patching it by ignoring the exception is not the right thing to do. Try to pin down why you are sending the wrong message to the wrong object instead. Your code will become more robust and maintainable.
Also, sometimes you get this exception when the object originally was of the right type, but is halfway in the process of being deallocated. Watch out!
If you still want to bypass the exception, read Apple's docs where it explains the multi-step process by which messages are bound to method implementations at run time. There is at least two places where you can catch it by overriding NSObject's default behavior.
I understand the answers telling you to prevent the unrecognized selector since that is the preferred method.
But in the case where you do not have that option (such as in my case, Cocoa internals messing up further down the call stack) you can indeed catch the unrecognized selector as you tried.
Proof of concept code:
// Do a really bad cast from NSObject to NSButton
// to get something to demonstrate on
NSButton *object = (NSButton*)[[NSObject alloc] init];
#try{
// Log the description as the method exists
// on both NSObject and NSButton
NSLog(#"%#", [object description]);
// Send an unrecognized selector to NSObject
[object bounds];
} #catch(NSException *e){
NSLog(#"Catch");
} #finally {
NSLog(#"Finally");
}
// Print the description to prove continued execution
NSLog(#"Description again: %#", [object description]);
Output:
2019-02-26 14:11:04.246050+0100 app[46152:172456] <NSObject: 0x60000000a6f0>
2019-02-26 14:11:04.246130+0100 app[46152:172456] -[NSObject bounds]: unrecognized selector sent to instance 0x60000000a6f0
2019-02-26 14:11:04.246226+0100 app[46152:172456] Catch
2019-02-26 14:11:04.246242+0100 app[46152:172456] Finally
2019-02-26 14:11:04.246258+0100 app[46152:172456] Description again: <NSObject: 0x60000000a6f0>
As you can see the exception is still logged to the console, but the code execution continues.
My main app controller invokes a subcontroller to handle a certain sequence of screens. The main controller sets itself as a delegate in the subcontroller. When the subcontroller is done doing its stuff, it notifies the delegate. Every now and then, this notification fails with EXC_BAD_ACCESS.
0)Based on gdb, the problem occurs in objc_msgSend. Both registers have a non-zero value.
gdb: 0x3367cc98 <+0016> ldr r5, [r4, #8]
1)I've tried NSZombiesEnabled to track the problem, but I couldn't reproduce it then.
2)I've tried setting a breakpoint just before the problematic command, but again I can't reproduce the issue.
I have no clue what's going on.
This is the delegate property declaration (the parent controller outlives the child):
#property (assign) id<ParentControllerDelegate> delegate
This is the problematic code:
- (void) doStuff {
if(mode == Done) {
NSLog(#"Done. Handling back control");//this is the last log displayed by the console
[self.delegate done: self];
} else {
// some controller code
}
This is the the code on the delegate side (the delegate has been retained by the App_Delegate, as it is the main controller).
- (void) done: (UIViewController *) caller {
NSLog(#"Taken back control");// this never displays
[caller.view removeFromSuperview];
[caller release];
}
Some extra info:
The main controller retains the subcontroller.
I've also modified the deallocs in both the main and sub controllers to log when it is called. Based on the visible logs, neither is ever called during the course of the application. Hence both the receiver and the sender of the message are valid objects.
I'm really at loss here. Looking forward to your help.
If the NSLog call in done: is never performed, that can only mean that you did not call the main controller's done:. That can mean that self.delegate is not valid. The objects may be valid and alive, but not the link (self.delegate) between them. Check that, please. In doStuff, in the "Done" branch, show the address of self.delegate with
NSLog(#"%p", self.delegate);
before you call done: and compare that with the address of the main controller.
Just a wild guess, but if it's "now and then" it's probably viewDidLoad or viewDidUnload causing the EXC_BAD_ACCESS after receiving memory warning. Check your released/retained/created instance variables in your parent/child controller especially in aforementioned view loading methods.
Try to perform check protocol and method before call as in the code:
- (void) doStuff
{
if(mode == Done)
{
NSLog(#"Done. Handling back control");//this is the last log displayed by the console
if ([delegate conformsToProtocol: #protocol(ParentControllerDelegate)])
{
if ([delegate respondsToSelector: #selector(done:)] == YES)
{
[delegate performSelector: #selector(done:) withObject: self];
}
}
}
else
{
// some controller code