【问题标题】:Order of events when loading a View in iOS在 iOS 中加载视图时的事件顺序
【发布时间】:2012-03-23 11:42:11
【问题描述】:

这个让我有点发疯,我的眼睛在掩饰。

我有一个带有导航控制器的应用。

视图 A 有一些输入字段和一个加载视图 B 的“继续”按钮

当我点击导航控制器左上角的“返回”按钮时,它会导致事件以我不期望/不理解的顺序触发

我的追踪揭示了......

View B: viewWillDisappear
View A: viewWillAppear
View B: textFieldShouldEndEditing

编辑 -- 更多细节/代码解释我之前含糊的问题

从概念上讲,以下方法运行良好,并通过了几轮 QA 测试。

总之,我使用textFieldShouldEndEditing 来验证文本字段。如果它们无效,我会继续关注该领域并向他们显示错误信息。一切都很好,并且当用户尝试从一个字段转到另一个字段时,验证工作。

以下代码存在问题的情况是,如果有人输入了部分值,然后单击了“返回”。整个应用程序中的所有UITextFields 冻结(不允许输入),在某些情况下应用程序崩溃。

我尝试发布初始问题的方法是创建一个私有的:BOOL isDisappearing;

我可以签入viewWillDisappear(在大多数情况下会在 textFieldShouldEndEditing 之前触发),如果是,我会将触发和冻结 UITextFields/app 的有问题的代码短路。

这在多个视图中都可以正常工作,但在 1 种情况下,“VIEW A:viewWillAppear”事件在下面的 textFieldShouldEndEditing(视图 B)之前触发 - isDisappearing 以某种方式设置为“NO”并且有问题的代码正在触发在textFieldShouldEndEditing

我希望这会有所帮助,您可以关注。我发现没有代码很难解释——但我试图将其精简为相关的内容。我希望这在这里是合适的——我对社区很陌生。

视图 B 的代码:

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)rangereplacementString:(NSString *)string
{   
    // Enforce max lengths
    // The return key from the keyboard counts as a character, so we have to exempt it
if (textField.tag == ROUTING_NUMBER_TAG)
{
    NSUInteger newLength = [textField.text length] + [string length] - range.length; 
    return (newLength > 9 && ![string isEqualToString:@"\n"]) ? NO : YES;           
}
else if (textField.tag == ACCOUNT_NUMBER_TAG)
{
    NSUInteger newLength = [textField.text length] + [string length] - range.length; 
    return (newLength > 17 && ![string isEqualToString:@"\n"]) ? NO : YES;           
}
return YES;
}

// textField validation
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
if (isDisappearing)

    return YES;

//run fields through validators and display validation messages.
//IF THEY DON’T PASS VALIDATION IM "HOLDING THEM HOSTAGE" BY KEEPING THE FOCUS ON THE UITEXTFIELD (returning NO)

if (textField.tag == ROUTING_NUMBER_TAG )
{
    if ([Utility isValidRoutingNumber:textField.text]== NO)
    {
        [[iToast makeText:NSLocalizedString(@"Enter valid routing number", @"")] show];
        return NO;
    }
    else
    {   //save it
         extension.payment.routingNumber = routingNumber.text;
    }
}
else if (textField.tag == ACCOUNT_NUMBER_TAG)
{
    if ([Utility isValidAccountNumber:textField.text] == NO)
    {
        [[iToast makeText:NSLocalizedString(@"Enter valid account number", @"")] show];
        return NO;
    }
    else
    {   //save it
        extension.payment.accountNumber = accountNumber.text;
    }
}
return YES;
}


- (void)textFieldDidEndEditing:(UITextField *)textField
{

//I do nothing here except nulling out the 'activefield' var I use to autoscroll the uiscrollview as the user taps around from field to field

}



- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];

//reset the bool so that when they come back we're back to the 'normal' state and validation will again be checked in textFieldShouldEndEditing

isDisappearing = NO;
}

- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}


-(void)viewWillDisappear:(BOOL)animated
{
TRC_ENTRY
//set the bool to bypass validations in textFieldShouldEndEditing

isDisappearing = YES;
[super viewWillDisappear:animated];
}

【问题讨论】:

    标签: iphone objective-c ios xcode


    【解决方案1】:

    除了名称明确定义或强烈暗示消息顺序的情况外,您应避免依赖任何特定顺序。例如,对于任何给定的视图,您可以合理地期望 -viewWillAppear-viewDidAppear 之前被调用,但不要期望一个视图的 -viewWillAppear 对于发送到不同视图的任何消息以任何特定顺序被调用。

    如果您需要帮助确定如何在不依赖顺序的情况下实现特定功能,请询问。但同样,除非调用顺序已记录在案或从方法名称中显而易见,否则不要期望特定的顺序。

    更新:我看不出您添加的代码到底出了什么问题,但也许一些建议会有所帮助:

    1. 您的isDisappearing 变量是视图控制器的实例变量、全局变量还是什么?如果它是一个实例变量,请弄清楚它是如何被改变的。如果它是一个全局变量,那么……不要那样做。

    2. 请确保您注意warning in the docs 的意思是-textViewShouldEndEditing: 只是建议性的,无论您返回什么视图都可能停止编辑。

    3. 尝试暂时删除 iToast 内容。如果崩溃仍然发生,至少你已经消除了它作为问题的根源。如果它停止发生,您将缩小搜索范围。

    4. 确定崩溃的原因。 (这确实应该排在第一位。)崩溃不只是神秘地发生——它发生是有原因的。找到那个原因,你就完成了 85%。首先检查崩溃发生时的堆栈跟踪。如果这不能提供足够的线索,请在导致崩溃的行之前的某处放置一个断点并开始单步执行直到崩溃。如果一切都失败了,请开始记录消息以跟踪执行情况并监控您的假设。

    5. 您的视图控制器 A 在其 -viewWillAppear 方法中究竟做了什么?这可能是问题的一部分吗?你能把这段代码移到-viewDidAppear吗?

    【讨论】:

    • 只是不小心过早地提交了我的评论。让我再试一次......我的问题似乎是 UITextFieldDelate 相关事件以意想不到的方式触发。我确信有一个合乎逻辑的原因,但在某些情况下 textFieldShouldEndEditing only 在 UITextField 具有焦点时单击 NavController“Back”按钮时触发。我在这种情况下的代码有效。我刚刚发现 textFieldDidEndEditing 在我遇到问题的情况下也会触发。我现在正试图弄清楚为什么 DID 在这种特殊情况下会触发,而在其他情况下不会触发。
    • @jayboston -textFieldShouldEndEditing: 应在文本字段即将放弃其“第一响应者”状态时调用。因此,如果您点击不同的文本字段,或者执行任何其他会使文本字段不再是第一响应者的操作,则应该为当前聚焦的文本字段调用它。这显然包括点击“后退”按钮,因为这将取代包括第一响应者在内的大部分响应者链。当文本字段肯定不再是第一响应者时,您是否有-textFieldDidEndEditing: 被调用的情况?
    • @jayboston 另外,请记住,如果您有多个具有相同委托的文本字段,则该对象将接收所有文本字段的消息。因此,您可能会得到一个字段的-textFieldShouldBeginEditing: 和一个不同的字段或其他组合的-textFieldDidEndEditing:,并且不一定按此顺序。密切关注sender参数。
    • 我认为您遇到了问题,可能是我对 UITextField 事件的误解,现在我完全质疑我的方法。我正在编辑我的问题,以包含我正在使用的代码,并更全面地描述我正在尝试完成的工作,希望有人能告诉我我是否已取消预订。我 am 使用标签来识别发件人等 - 我想我已经掌握了它。我希望您有时间看看让我感到悲伤的代码并让我理顺
    • 感谢 Caleb 的精彩提示。我遇到了一些事情,但会在接下来的几天里回到这个问题上并尝试你的建议。 isDisappearing 是一个实例变量,但神秘地似乎失去了它的范围/值。我想过把它变成一个属性,看看这是否会有所作为,但它似乎不应该。很快回来,感谢所有的帮助。
    【解决方案2】:

    这可能与您的问题没有直接关系,但如果您觉得您不完全了解视图的生命周期,我建议您看这里:What is the process of a UIViewController birth (which method follows which)?

    这是一个很好的解释。

    【讨论】:

    • 谢谢。我很好地理解了视图生命周期。我遇到的问题似乎是 textField 事件开始起作用时。我正在使用 UITextFieldDelegate 并在这些事件中处理大量字段验证
    【解决方案3】:

    尝试在视图 B viewWillDisappear 上执行 [self.youTextField resignFirstResponder]

    【讨论】:

      猜你喜欢
      • 2023-03-21
      • 1970-01-01
      • 2012-01-30
      • 2012-04-19
      • 2019-06-30
      • 1970-01-01
      • 2012-07-25
      • 2010-11-28
      • 1970-01-01
      相关资源
      最近更新 更多