On Jul 26, 2009, at 1:18 AM, WT wrote:

On Jul 26, 2009, at 1:04 AM, WT wrote:

Now, I agree that UITextField will run into an infinite loop (in the sample app) when calling -respondsToSelector on its delegate because it is its own delegate. However, why is it then that - textFieldShouldBeginEditing returns successfully and - textFieldDidBeginEditing executes but doesn't return? Both of them successfully print their method names:

- (BOOL) textFieldShouldBeginEditing: (UITextField*) text_field
{
  NSLog(@"-textFieldShouldBeginEditing:");
  return YES;
}

- (void) textFieldDidBeginEditing: (UITextField*) text_field
{
  NSLog(@"-textFieldDidBeginEditing:");
}

It would seem that -respondsToSelector: is not being called at all.

Actually, it is and I do get an infinite loop, thanks to

- (BOOL) respondsToSelector: (SEL) selector
{
   NSLog(@"-respondsToSelector:");
   return [super respondsToSelector: selector];
}

How do I get a string for the name of the method represented by the selector?

I'm beginning to understand the intricacies of this problem... First, since I don't know how to get the name of a method (as a string) from its selector, I'm simply outputting the selector itself, which is an address. Now, consider this as the subclass implementation:

#import "CustomTextField.h"

@implementation CustomTextField

- (void) awakeFromNib
{
    super.delegate = self;
    super.text = @"Hello world";

    NSLog(@"awakeFromNib called - delegate set to self");
}

// = = = = ===================================================================== //

- (BOOL) textField: (UITextField*) text_field
         shouldChangeCharactersInRange: (NSRange) range
         replacementString: (NSString*) string
{
NSLog(@"-textField: shouldChangeCharactersInRange: replacementString: %p", @selector(textField: shouldChangeCharactersInRange: replacementString:));
    return YES;
}

// = = = = ===================================================================== //

- (BOOL) textFieldShouldBeginEditing: (UITextField*) text_field
{
    NSLog(@"-textFieldShouldBeginEditing: %p",
          @selector(textFieldShouldBeginEditing:));
    return YES;
}

// = = = = ===================================================================== //

- (void) textFieldDidBeginEditing: (UITextField*) text_field
{
    NSLog(@"-textFieldDidBeginEditing: %p",
          @selector(textFieldDidBeginEditing:));
}

// = = = = ===================================================================== //

- (BOOL) textFieldShouldEndEditing: (UITextField*) text_field
{
    NSLog(@"-textFieldShouldEndEditing: %p",
          @selector(textFieldShouldEndEditing:));
    return YES;
}

// = = = = ===================================================================== //

- (void) textFieldDidEndEditing: (UITextField*) text_field
{
    NSLog(@"-textFieldDidEndEditing: %p",
          @selector(textFieldDidEndEditing:));
}

// = = = = ===================================================================== //

- (BOOL) textFieldShouldClear: (UITextField*) text_field
{
    NSLog(@"-textFieldShouldClear: %p",
          @selector(textFieldShouldClear:));
    return YES;
}

// = = = = ===================================================================== //

- (BOOL) textFieldShouldReturn: (UITextField*) text_field
{
    NSLog(@"-textFieldShouldReturn: %p",
          @selector(textFieldShouldReturn:));
    [self resignFirstResponder];
    return YES;
}

// = = = = ===================================================================== //

- (BOOL) respondsToSelector: (SEL) selector
{
    NSLog(@"-respondsToSelector: %p", selector);

    if (selector ==
@selector(textField:shouldChangeCharactersInRange:replacementString:) ||
        selector == @selector(textFieldShouldBeginEditing:) ||
        selector == @selector(textFieldDidBeginEditing:) ||
        selector == @selector(textFieldShouldEndEditing:) ||
        selector == @selector(textFieldDidEndEditing:) ||
        selector == @selector(textFieldShouldClear:) ||
        selector == @selector(textFieldShouldReturn:))
    { return YES; }
    else
    {
        return [UITextField instancesRespondToSelector: selector];
    }
}

// = = = = ===================================================================== //

@end

This still causes an infinite loop, with the result being something like this:

-respondsToSelector: 0x93147998
-respondsToSelector: 0x9316a1b4
-respondsToSelector: 0x931bf364
-respondsToSelector: 0x931389bc
-respondsToSelector: 0x93142b98
-respondsToSelector: 0x931d30c4
-respondsToSelector: 0x93167564
-respondsToSelector: 0x319b8c98
-respondsToSelector: 0x319cc41a
-respondsToSelector: 0x319f4af4
awakeFromNib called - delegate set to self
-respondsToSelector: 0x319b5a68
-textFieldShouldBeginEditing: 0x319b5a68
-respondsToSelector: 0x319aa222
-respondsToSelector: 0x319aa124
-respondsToSelector: 0x319aa100
-respondsToSelector: 0x319aa387
-respondsToSelector: 0x319c9f98
-respondsToSelector: 0x319f4af4
-respondsToSelector: 0x319f4af4
-respondsToSelector: 0x319f4af4
-respondsToSelector: 0x319f4af4
-respondsToSelector: 0x319aa25c
-respondsToSelector: 0x319aade0
-respondsToSelector: 0x319f55a4
-textFieldDidBeginEditing: 0x319f55a4
-respondsToSelector: 0x319c9f98
-respondsToSelector: 0x319f4af4
-respondsToSelector: 0x319c9f98
-respondsToSelector: 0x319f4af4
-respondsToSelector: 0x319b8c98
-respondsToSelector: 0x319cc41a
-respondsToSelector: 0x319f4af4
-respondsToSelector: 0x319caae2
-respondsToSelector: 0x319caae2
-respondsToSelector: 0x319caae2
-respondsToSelector: 0x319caae2
...

So, even though it's responding correctly to the text field delegate methods, it's recursing infinitely when calling -respondsToSelector with the selector at address 0x319caae2. The reason it's doing that is what Kyle already pointed out: the delegate pattern is such that when - respondsToSelector: returns NO, the delegate is queried, also with a call to -respondsToSelector. In this case, the text field is its own delegate, hence the infinite loop.

Naturally, replacing the code inside the else block to return NO is the wrong thing to do because then (a) it would still loop and (b) it would be returning NO for *all* delegate methods other than those in the UITextFieldDelegate protocol. Replacing the code there to return YES is also wrong since some delegate methods might not be implemented and the app would crash.

It seems I'll have to opt for having a regular UITextField and a custom class whose sole purpose is to provide a delegate that does the common work. As Kyle suggested, I may need to make that a superclass and derive additional delegates to perform extra work after the common task.

It's a shame... I would have preferred the solution I had in mind, because - to me - that's a very clean solution. Too bad it doesn't work.

Thanks to all who pitched in and to Kyle in particular, for nailing the issue for me.

Wagner

_______________________________________________

Cocoa-dev mailing list ([email protected])

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to