-->

Error when ViewController is implementing UITextFi

2019-09-17 10:10发布

问题:

When implementing the UITextFieldDelegate in my ViewController class, the following error is thrown when entering the first character in the text field:

-[MyViewController respondsToSelector:]: message sent to deallocated instance...

So, I tried creating a separate class (inheriting only NSObject) and implementing UITextFieldDelegate. Guess what, it worked perfectly. However, that introduces some other problems as I have to do a lot of ugly cross-class-communication that I'd like to avoid. Here's the relevant parts of my app delegate code:

@interface RMSAppDelegate : NSObject <UIApplicationDelegate,
                                      UITabBarControllerDelegate>

@property (nonatomic, retain) UIViewController* myViewController;

@end

@implementation MyAppDelegate

@synthesize myViewController;

- (BOOL)application:(UIApplication *)application
            didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    myViewController = [[MyViewController alloc]
                         initWithNibName:@"MyView" bundle:nil];
    [self.window setRootViewController:myViewController];
    [self.window makeKeyAndVisible];
    return YES;
}

@end

.. and here's what is being displayed:

@interface MyViewController : UIViewController <UITextFieldDelegate>

@property (nonatomic, retain) IBOutlet UITextField* pinTextField;
- (void)viewDidLoad;

@end

@implementation MyViewController

@synthesize pinTextField;

- (void)viewDidLoad {
    // DOES NOT WORK (WHY?)
    //[pinTextField setDelegate:self];

    // WORKS, BUT I'D LIKE TO AVOID
    [pinTextField setDelegate:[[[MyTextFieldDelegate alloc] init] autorelease];

    [pinTextField becomeFirstResponder];
    [super viewDidLoad];
}

@end

And please, if you see any code (even off topic) that I could be doing better, leave a comment.

回答1:

Since you asked for off-topic code comments: You forget to call [super viewDidLoad]. You also don't need to redeclare the prototype in order to override it. And the @synthesize textFieldDelegate is not valid, as you have no property in the class named textFieldDelegate. And your dealloc method is releasing an ivar named tfd which doesn't seem to actually exist in the class.

Your real problem is that you are not properly retaining the view controller at whatever point you allocate it. It may be that the view controller is being instantiated in a nib and associated with an ivar rather than a property declared retain, or is not being associated with anything. Or it could be that you are allocating it in code, adding its view as a subview of something, and then releasing it without ever retaining the view controller itself. Or it could just be that you are just releasing it when you shouldn't.

Your other class works specifically because you are leaking the object, so it never gets deallocated. The better solution, were you to go with this method, would be to store the object in an ivar when you allocate it and then release it (and set the ivar to nil) in both dealloc and viewDidUnload.



回答2:

Okay, I finally solved this on my own. I have not changed the code. My NIB (.xib) was the culprit!

I thought that nested UIViewControllers was OK, and I still think they are in some cases (and maybe using another programmatic method). Anyway, I was initializing my class MyViewController with a NIB that in the Objects panel had a UIViewController as the first object.

I solved this by having the UIView as the first object in the Objects panel, and setting the File's Owner to be the UIViewController instead.

Correct code, incorrect NIB. Thank you for your help.