在开发iOS的过程中,我们都会遇到许多有UITextField的页面,有的页面还不只一个。当我们提交填写的表单时,都会判断,是不是每个输入框都填写完成。效果如下:
如上图,当页面输入框都输入完毕后,才能做下一步操作!但是要每个输入框页面都做判断的话,很麻烦!
所以我们可以利用runtime,提前在BaseViewController里面做好所有判断操作,让有输入框的界面继承Base,通过runtime父类遍历出子类的成员,拿到子类页面所有输入框!这样省了很多事了!
具体代码如下:
BaseViewController.h
#import <UIKit/UIKit.h>
#import "UIButton+toos.h"
@interface BaseViewController : UIViewController
//告诉子类是否所有输入框是否填写完毕的block
@property(nonatomic,copy)void(^isOKBlock)(BOOL isOk);
@end
BaseViewController.m
#import "BaseViewController.h"
//首先导入runtime库
#import <objc/runtime.h>
@interface BaseViewController ()<UITextFieldDelegate,UITextViewDelegate>
{
BOOL isOK;//用来判断是否所有输入框都输入完毕
}
@property(nonatomic,strong)NSMutableDictionary * dic;
@end
@implementation BaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
//刚进来,肯定没输入!所以为NO
isOK =NO;
self.dic = [NSMutableDictionary dictionary];
//因为我们这里是父类,父类调用子类只能通过runtime做到! 下面利用runtime遍历子类的成员变量
unsigned int outCount = 0;
Ivar * ivars = class_copyIvarList([self class], &outCount);
for (unsigned int i = 0; i < outCount; i ++) {
Ivar ivar = ivars[i];
const char * name = ivar_getName(ivar);//获取成员变量名字
const char * type = ivar_getTypeEncoding(ivar);//获取成员的原型
if (strcmp(type, "@\"UITextField\"") == 0)//如果type是UITextField就进入方法
{
NSString * s = [NSString stringWithFormat:@"%s",name];//UITextField的名称
UITextField * field = [(UITextField * )self valueForKey:s];//获取UITextField
field.delegate = self;//签代理
//监听UITextField改变的方法
[field addTarget:self action:@selector(textFieldWithText:) forControlEvents:UIControlEventEditingChanged];
//下面这行是利用字典记录UITextField的个数,以及内容
[self.dic setValue:@"" forKeyPath:[NSString stringWithFormat:@"%d",i+100]];
}
if (strcmp(type, "@\"UITextView\"") == 0) {
NSString * s = [NSString stringWithFormat:@"%s",name];
UITextView * field = [(UITextField * )self valueForKey:s];
field.delegate = self;
}
}
free(ivars);
// Do any additional setup after loading the view.
}
- (void)textFieldWithText:(UITextField *)textField
{
unsigned int outCount = 0;
Ivar * ivars = class_copyIvarList([self class], &outCount);
for (unsigned int i = 0; i < outCount; i ++) {
Ivar ivar = ivars[i];
const char * name = ivar_getName(ivar);
const char * type = ivar_getTypeEncoding(ivar);
if (strcmp(type, "@\"UITextField\"") == 0)
{
NSString * s = [NSString stringWithFormat:@"%s",name];
UITextField * field = [(UITextField * )self valueForKey:s];
//每个输入框的改变,字典的value都会一起改变。
[self.dic setValue:field.text forKeyPath:[NSString stringWithFormat:@"%d",i+100]];
}
}
free(ivars);
isOK = YES;//这里的意思是,输入后,先给你个YES 然后走下面的代码
for (NSString * string in [self.dic allValues]) {
if (string.length<1) {//只要发现输入后有输入框的值为空就为NO
isOK =NO;
}
}
//下面就是返回结果给子类
if (self.isOKBlock) {
self.isOKBlock(isOK);
}
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[[[UIApplication sharedApplication] keyWindow] endEditing:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
在子类中调用父类的block就可以了
[_button setNotOptionalBut];
__weak typeof(self)weakself = self;
self.isOKBlock = ^(BOOL isOK){
if (isOK) {//输入完毕
[weakself.button setOptionalBut];
}else{//没输入完
[weakself.button setNotOptionalBut];
}
};
这是监听结果的改变!这样就方便了许多!
demo地址:https://github.com/zezeyu/iOS-demo
谢谢观看!