Почему resignFirstResponder вызывается дважды в iOS 5.0, но только один раз в iOS4.2-4.3? - PullRequest
7 голосов
/ 13 октября 2011

У меня есть приложение в App Store, скомпилированное для 4.2, которое работает странно при работе под iOS 5.0. Я отследил его до resignFirstResponder, который вызывался дважды под iOS 5.0, тогда как он вызывался только один раз под iOS 4.2 и 4.3.

У меня есть производный класс от UITextField, где я переопределяю resignFirstResponder. Смотрите пример кода ниже.

Под iOS 4.2 и 4.3 я вижу в консоли следующее:

textFieldShouldReturn
resignFirstResponder
textFieldDidEndEditing

Под iOS 5.0 я вижу в консоли следующее:

textFieldShouldReturn
resignFirstResponder
resignFirstResponder
textFieldDidEndEditing

Запуск кода на устройстве и симуляторе дает постоянные результаты. Я что-то упустил или это ошибка?

Трассировка стека iOS 5.0

#0  -[BugTextField resignFirstResponder] (self=0x681b530, _cmd=0x3769b41) at /Users/.../BugTextField.m:14
#1  0x006c05a6 in -[UIFieldEditor resignFirstResponder] ()
#2  0x006374e3 in -[UIView(Hierarchy) _willMoveToWindow:] ()
#3  0x006362c2 in __UIViewWillBeRemovedFromSuperview ()
#4  0x006360d7 in -[UIView(Hierarchy) removeFromSuperview] ()
#5  0x006bfff7 in -[UIFieldEditor becomeFieldEditorForView:] ()
#6  0x006ae37b in -[UITextField _resignFirstResponder] ()
#7  0x006eb8d4 in -[UIResponder _finishResignFirstResponder] ()
#8  0x006eba20 in -[UIResponder resignFirstResponder] ()
#9  0x006ae249 in -[UITextField resignFirstResponder] ()
#10 0x00017f68 in -[BugTextField resignFirstResponder] (self=0x681b530, _cmd=0x3769b41) at /Users/.../BugTextField.m:16
#11 0x0001828f in -[BugTextFieldVC textFieldShouldReturn:] (self=0x6829750, _cmd=0x18c5b, textField=0x681b530) at /Users/.../BugTextFieldVC.m:40

BugTextField.h

#import <UIKit/UIKit.h>

@interface BugTextField : UITextField

@end

BugTextField.m

#import "BugTextField.h"

@implementation BugTextField

- (BOOL) resignFirstResponder
{
    NSLog(@"resignFirstResponder");

    return [super resignFirstResponder];
}

@end

BugTextFieldVC.h

#import <UIKit/UIKit.h>
@class BugTextField;

@interface BugTextFieldVC : UIViewController <UITextFieldDelegate> {
    BugTextField *bugTextField;
}

@end

BugTextFieldVC.m

#import "BugTextFieldVC.h"
#import "BugTextField.h"

@implementation BugTextFieldVC

- (id) init
{
    if ( !(self = [super init]) )
    {
        return self;
    }

    // One text field with 100 height keyboard
    bugTextField = [[BugTextField alloc] initWithFrame:CGRectMake(10, 10, 300, 30)];
    bugTextField.borderStyle = UITextBorderStyleRoundedRect;
    bugTextField.delegate = self;
    [self.view addSubview:bugTextField];

    return self;
}

- (void) dealloc
{
    [bugTextField release];

    [super dealloc];
}

- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
    NSLog(@"textFieldShouldReturn");

    [textField resignFirstResponder];

    return YES;
}

- (void) textFieldDidEndEditing:(UITextField *)textField
{
    NSLog(@"textFieldDidEndEditing");
}

@end

Ответы [ 2 ]

1 голос
/ 13 октября 2011

Ниже представлен обходной путь, который работает для iOS 4.2, 4.3 и 5.0. Это не ракетостроение и не сексуальность, но это будет работать, пока я не пойму лучше, что происходит (я делаю что-то не так или этоошибка?).Я сообщаю об этом как об ошибке в Apple.

BugTextField.h

#import <UIKit/UIKit.h>

@interface BugTextField : UITextField {
    // Value used to ensure code in resignFirstResponder is executed by the 
    // first stack frame and not subsequent stack frames in iOS 5.0.
    //
    // In iOS 5.0, one call to resignFirstResponder results in a second call to
    // resignFirstResponder.  In iOS 4.2 & 4.3, one call to resignFirstResponder
    // does not result in subsequent calls to resignFirstResponder.
    NSUInteger resignFirstResponderCallDepth;
}

@end

BugTextField.m

#import "BugTextField.h"

@implementation BugTextField

- (BOOL) resignFirstResponder
{
    if (0 == resignFirstResponderCallDepth++)
    {
        // ---------------------------------------------------------------------
        // Code executed by first stack frame to call resignFirstResponder.
        NSLog(@"resignFirstResponder");
    }

    // -------------------------------------------------------------------------
    // Code executed by every stack frame to call resignFirstResponder.
    BOOL rV = [super resignFirstResponder];

    resignFirstResponderCallDepth--;

    return rV;
}

@end
0 голосов
/ 20 февраля 2012

Одним из решений является переопределение canResignFirstResponder. Это будет вызвано только один раз.

Проблема в том, что это не согласуется с документами - https://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIResponder_Class/Reference/Reference.html - так что вы, вероятно, правы: это ошибка.

...