1

This is the weirdest thing I've ever encountered, and the problem is consistent across an iPhone 4 and iPhone 5s...

I've created a subclass of UITextField to add some custom functionality, and have set a UITextField's custom class to my custom class in the storyboard.

Great, all good - but.. Anytime I tap to open the field, I can type fine - as soon as I hit the emoji globe part of the keyboard, the app instantly locks up. It doesn't crash, I just cannot do anything, the typing indicator stops blinking and the app just hangs infinitely..

So very strange.

Here's the custom class I've created.

Header

#import <UIKit/UIKit.h>

@interface GenericTextField : UITextField <UITextFieldDelegate>

@property id nextField;
@property id nextCallbackTarget;
@property SEL nextCallbackSelector;

@end

Implementation

#import "GenericTextField.h"

@implementation GenericTextField

- (id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder]) {
        [self setup];
    }
    return self;
}

- (void)setup
{
    self.delegate = self;
}

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
    return YES;
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    if ([self.nextField respondsToSelector:@selector(becomeFirstResponder)]) {
        [self.nextField becomeFirstResponder];
    } else {
        [self resignFirstResponder];
        if ([self.nextCallbackTarget respondsToSelector:self.nextCallbackSelector]) {
            #pragma clang diagnostic push
            #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            [self.nextCallbackTarget performSelector:self.nextCallbackSelector];
            #pragma clang diagnostic pop
        }
    }

    return NO;
}

@end

Here's another interesting part. If I comment out the portion where I'm setting the delegate to self, everything works fine.. However, if I comment out my custom delegate methods and keep the delegate set to self in the setup method, I still get the freeze. This seems to be specifically linked to setting the delegate? Why? Does it have to do with setting it to self from the initWithCoder? If so, why does it just happen in UITextField and none of my other custom classes that set delegates to self like in a UIScrollView subclass I've made?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Braydon Batungbacal
  • 1,028
  • 2
  • 24
  • 52
  • Also, my phone starts getting hot when it hang.. Which makes me think somethings stuck in a loop. Still searching... – Braydon Batungbacal Jun 19 '14 at 22:39
  • I believe this is the problem. http://stackoverflow.com/questions/1747777/self-delegate-self-whats-wrong-in-doing-that – Braydon Batungbacal Jun 19 '14 at 22:40
  • Run your app in Xcode. When it appears to freeze, give it a few seconds then tap the "pause" icon in the debugger. Look at the stack traces in the left side of the debugger. What's going on? – rmaddy Jun 19 '14 at 22:42

1 Answers1

3

Alright, took a little searching but maybe this answer will help anyone trying to figure it out.

UITextField is unique AFAIK. You can usually use a class as its own delegate with no particular problems. For UITextField you must create an actual delegate (that could, of course, call methods on the UITextField for which it's a delegate. Just be careful to avoid retain loops, even if you're using ARC).

Which led me to trying some updated code in my implantation and creating a shared delegate class for handling the delegate in the simplest way I could think of. Here's the updated implementation.

Hope it helps!

#import "GenericTextField.h"

@interface GenericTextFieldDelegate : NSObject <UITextFieldDelegate>
+ (GenericTextFieldDelegate *)sharedDelegate;
@end

@implementation GenericTextFieldDelegate

+ (GenericTextFieldDelegate *)sharedDelegate
{
    static GenericTextFieldDelegate *genericTextFieldDelegate;
    @synchronized(self) {
        if (!genericTextFieldDelegate) {
            genericTextFieldDelegate = [[GenericTextFieldDelegate alloc] init];
        }
    }

    return genericTextFieldDelegate;
}

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
    return YES;
}

- (BOOL)textFieldShouldReturn:(GenericTextField *)textField
{
    if ([textField.nextField respondsToSelector:@selector(becomeFirstResponder)]) {
        [textField.nextField becomeFirstResponder];
    } else {
        [textField resignFirstResponder];
        if ([textField.nextCallbackTarget respondsToSelector:textField.nextCallbackSelector]) {
            #pragma clang diagnostic push
            #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            [textField.nextCallbackTarget performSelector:textField.nextCallbackSelector];
            #pragma clang diagnostic pop
        }
    }

    return NO;
}

@end

@implementation GenericTextField

- (id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder]) {
        [self setup];
    }
    return self;
}

- (void)setup
{
    self.delegate = [GenericTextFieldDelegate sharedDelegate];
}

@end
Braydon Batungbacal
  • 1,028
  • 2
  • 24
  • 52