Ios UISwitch value changed事件在UITextField编辑结束之前激发

Ios UISwitch value changed事件在UITextField编辑结束之前激发,ios,uitextfield,uikit,uiswitch,uicontrolevents,Ios,Uitextfield,Uikit,Uiswitch,Uicontrolevents,在我的应用程序中,在UITableViewCells列表中显示了许多UISwitches和UITextFields 当用户开始编辑UITextField然后点击UITextField时,事件的顺序会导致UITextField显示UITextField的值,因为事件处理程序没有收到UITextField的结束编辑事件 如何可靠地确保在ui开关的UIControlEventValueChanged之前触发UITextField的UIControlEventEditingDidEnd事件 它会导致如下

在我的应用程序中,在
UITableViewCell
s列表中显示了许多
UISwitch
es和
UITextField
s

当用户开始编辑
UITextField
然后点击
UITextField
时,事件的顺序会导致
UITextField
显示
UITextField
的值,因为事件处理程序没有收到
UITextField
的结束编辑事件

如何可靠地确保在
ui开关的
UIControlEventValueChanged
之前触发
UITextField
UIControlEventEditingDidEnd
事件

它会导致如下错误(文本字段中显示的开关值):

步骤(应发生的情况):

1.点击
ui开关
将其激活

UISwitch:startEditing:switch243
UISwitch:valueChanged:{true}
UISwitch:endEditing
UIEventHandler:saveValue:switch243:{true}
UITextField:endEditing
UISwitch:startEditing:switch243
UISwitch:valueChanged:{false}
UISwitch:endEditing
UIEventHandler:saveValue:switch243:{false}
2.点击
UITextField
开始编辑它

UITextField:startEditing:textfield455
3.点击
ui开关
,将其停用

UISwitch:startEditing:switch243
UISwitch:valueChanged:{true}
UISwitch:endEditing
UIEventHandler:saveValue:switch243:{true}
UITextField:endEditing
UISwitch:startEditing:switch243
UISwitch:valueChanged:{false}
UISwitch:endEditing
UIEventHandler:saveValue:switch243:{false}
控制台日志(实际发生的情况-UISwitch事件在UITextField:endEditing之前激发):

实施:

UITableViewCellWithSwitch.h

@interface UITableViewCellWithSwitch : UITableViewCell
@property (nonatomic, strong) NSString *attributeID;
@property (nonatomic, retain) IBOutlet UISwitch *switchField;
@end
@interface UITableViewCellWithTextField : UITableViewCell<UITextFieldDelegate>
@property (nonatomic, strong) NSString *attributeID;
@property (strong, nonatomic) IBOutlet UITextField *inputField;
@end
UITableViewCellWithSwitch.m

@implementation UITableViewCellWithSwitch
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self.switchField addTarget:self
                            action:@selector(switchChanged:)
                  forControlEvents:UIControlEventValueChanged];
    }
    return self;
}
// UIControlEventValueChanged
- (void)switchChanged:(UISwitch *)sender {
    NSLog(@"UISwitch:startEditing:%@",self.attributeID);
    [self handleStartEditingForAttributeID:self.attributeID];

    NSString* newValue = sender.on==YES?@"true":@"false";
    NSLog(@"UISwitch:valueChanged:{%@}", newValue);
    [self handleValueChangeForEditedAttribute:newValue];

    NSLog(@"UISwitch:endEditing");
    [self handleEndEditingForEditedAttribute];
}
@end
@implementation UITableViewCellWithTextField
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self.inputField addTarget:self
                            action:@selector(textFieldDidBegin:)
                  forControlEvents:UIControlEventEditingDidBegin];

        [self.inputField addTarget:self
                            action:@selector(textFieldDidChange:)
                  forControlEvents:UIControlEventEditingChanged];

        [self.inputField addTarget:self
                            action:@selector(textFieldDidEnd:)
                  forControlEvents:UIControlEventEditingDidEnd];
    }
    return self;
}
// UIControlEventEditingDidBegin
-(void) textFieldDidBegin:(UITextField *)sender {
    NSLog(@"UITextField:startEditing:%@",self.attributeID);
    [self handleStartEditingForAttributeID:self.attributeID];
}
// UIControlEventEditingChanged
-(void) textFieldDidChange:(UITextField *)sender {
    NSLog(@"UITextField:valueChanged:{%@}", sender.text);
    [self handleValueChangeForEditedAttribute:sender.text];
}
// UIControlEventEditingDidEnd
-(void) textFieldDidEnd:(UITextField *)sender {
    NSLog(@"UITextField:endEditing");
    [self handleEndEditingForEditedAttribute];
}
@end
UITableViewCellWithTextField.h

@interface UITableViewCellWithSwitch : UITableViewCell
@property (nonatomic, strong) NSString *attributeID;
@property (nonatomic, retain) IBOutlet UISwitch *switchField;
@end
@interface UITableViewCellWithTextField : UITableViewCell<UITextFieldDelegate>
@property (nonatomic, strong) NSString *attributeID;
@property (strong, nonatomic) IBOutlet UITextField *inputField;
@end
聚合所有UI编辑事件的
UIEventHandler.m

-(void) handleStartEditingForAttributeID:(NSString *)attributeID { 
    // Possible solution   
    //if (self.editedAttributeID != nil && [attributeID isEqualToString:self.editedAttributeID]==NO) { // Workaround needed for UISwitch events
    //    [self handleEndEditingForActiveAttribute];
    //}
    self.editedAttributeID = attributeID;
    self.temporaryValue = nil;
}

-(void) handleValueChangeForEditedAttribute:(NSString *)newValue {
    self.temporaryValue = newValue;
}

-(void) handleEndEditingForEditedAttribute { 
    if (self.temporaryValue != nil) { // Only if value has changed
        NSLog(@"UIEventHandler:saveValue:%@:{%@}", self.editedAttributeID, self.temporaryValue);

        // Causes the view to regenerate
        // The UITextField loses first responder status and UIControlEventEditingDidEnd is gets triggered too late
        [self.storage saveValue:self.temporaryValue 
                   forAttribute:self.editedAttributeID];

        self.temporaryValue = nil;
    }
    self.editedAttributeID = nil;
}

如果我理解正确的话,您遇到的问题是当一个textfield作为第一个响应程序更改开关值时,您的textfield的文本将更新为开关的值

只有当文本字段退出第一响应者时,才会发生
UITextField
didEndEditing:
事件。如果您要做的只是确保当开关值更改时文本字段结束编辑,则当开关接收到
UIControlEventValueChanged
事件时,应向活动文本字段发送
endEditing:
消息

现在,如何调用文本字段上的
endEditing:
消息取决于类的结构。您可以在表视图单元格类上有一个指定的初始值设定项方法,在该方法中传递与控制文本字段的
UISwitch
相对应的
UITextField
的实例。保持对textfield实例的弱引用,然后在开关值更改时调用
endEditing:
。或者,您可以简单地调用
[self-endEditing:YES]开关更改时,
UITableViewCellWithSwitch上的code>:
事件被触发或
[self.superview endEditing:YES]。我更喜欢前者而不是后者,因为后者更像是一个黑客而不是一个合适的解决方案

更新:

在检查代码之后,请说明问题中提到的错误原因

它会导致如下错误(文本字段中显示的开关值):

下面是一段代码:

- (void)switchChanged:(UISwitch *)sender {
    NSLog(@"UISwitch:startEditing:%@",self.attributeID);
    [self handleStartEditingForAttributeID:self.attributeID];

    NSString* newValue = sender.on==YES?@"true":@"false";
    NSLog(@"UISwitch:valueChanged:{%@}", newValue);
    [self handleValueChangeForEditedAttribute:newValue];

    NSLog(@"UISwitch:endEditing");
    [self handleEndEditingForEditedAttribute];
}
您正在调用
HandleValueChangeForEditeAttribute:
,该属性的开关值实际上应该只保存textfield的值。在
UIEventHandler
类中,您正在使用
handleEndeditingForeditAttribute
方法中的开关值更新数据访问对象(DAO)。将
开关changed:
方法的逻辑更改为以下内容:

- (void)switchChanged:(UISwitch *)sender {
    if (sender.on == YES) {
        [self handleStartEditingForAttributeID:self.attributeID];
    } else {
        [self handleEndEditingForEditedAttribute];
    }
}
在您的
UIEventHandler
类中,取消注释帖子中显示“可能的解决方案”的注释行。这将确保在存储新的
attributeID
的值之前保存以前的任何更改

-(void) handleStartEditingForAttributeID:(NSString *)attributeID { 
    // Possible solution   
    if (self.editedAttributeID != nil && [attributeID isEqualToString:self.editedAttributeID]==NO) { // Workaround needed for UISwitch events
        [self handleEndEditingForActiveAttribute];
    }
    self.editedAttributeID = attributeID;
    self.temporaryValue = nil;
}

我最好的解决方案是在
UIEventHandler.m
中解决这个问题。如果调用
startEditing
时未触发
endEditing
事件,则会从
UIEventHandler
调用该事件

-(void) handleStartEditingForAttributeID:(NSString *)attributeID { 
    // Possible solution   
    if (self.editedAttributeID != nil && [attributeID isEqualToString:self.editedAttributeID]==NO) { // Workaround needed for UISwitch events
        [self handleEndEditingForActiveAttribute];
    }
    self.editedAttributeID = attributeID;
    self.temporaryValue = nil;
}

-(void) handleValueChangeForEditedAttribute:(NSString *)newValue {
    self.temporaryValue = newValue;
}

-(void) handleEndEditingForEditedAttribute { 
    if (self.temporaryValue != nil) { // Only if value has changed
        NSLog(@"UIEventHandler:saveValue:%@:{%@}", self.editedAttributeID, self.temporaryValue);

        // Causes the view to regenerate
        // The UITextField loses first responder status and UIControlEventEditingDidEnd is gets triggered too late
        [self.storage saveValue:self.temporaryValue 
                   forAttribute:self.editedAttributeID];

        self.temporaryValue = nil;
    }
    self.editedAttributeID = nil;
}

您需要提供有关代码正在执行的操作的更多信息。从您所展示的内容来看,点击开关“deactivate it”除了执行两条log语句外,什么也不做。看看你想在Switch上实现什么?@MohammadSadiq我需要按
UIEventHandler.m
@PeterGerhat使用的每个输入字段类型(开始编辑、值更改、结束编辑)调用3个事件-当你只发布部分代码时,任何人都很难提供帮助。例如,现在您有两个
textfielddibegen
方法?此外,没有任何信息表明发件人.attributeID
来自何处?@DonMag在问题中添加了更多细节。这是一个关于UIKit中事件处理的问题,特别是UISwitch和UITextField。不要使其过于宽泛。这是正确的
[self.storage saveValue]
会导致整个视图重新生成,这会导致
UITextField
失去第一响应程序状态,并在太晚时触发
uicontrolEventEditingDiEnd
。我开始认为,由于我的应用程序的体系结构,解决它的最佳位置是
UIEventHandler.m
(请参阅可能的解决方案)。@PeterGerhat你是对的。查看我的最新答案。我更新了您的
开关更改:
似乎您不知道
开关更改:
应该如何工作。它必须按该顺序触发
开始编辑
值更改
结束编辑
事件,才能使
UIEventHandler
正常工作。我在许多不同的UI输入组件中使用此事件模型,因此我无法将其专门用于
UISwitch
。@PeterGerhat收到了。如果这种设计在你的应用程序中是通用的,我想说你最好的选择是你在下面发布的解决方案,或者在你的表视图单元格或其父视图中调用
[self.view endEditing:YES]
,以触发
UITextField
的did end编辑事件。