这个例子是我在网上看到的,主要介绍了用KVC和Runtime更改UITextField默认提示文字(PlaceHolder)颜色,借此机会简单介绍一下KVC和Runtime。附Demo地址:(点击我,免积分哦)
目录:
- KVC
概念
常用方法
常用场景 - Runtime
概念
常用方法
使用场景 - Demo实现
运用KVC实现动图效果
运用Runtime实现动图效果
一、KVC (Key-value coding)键值编码
1.1)、简介
通过Key名直接访问对象的属性,或者给对象的属性赋值,而不需要调用明确的存取方法。这样就可以在运行,时动态在访问和修改对象的属性。而不是在编译时确定,这也是iOS开发中的黑魔法之一。
通常我们使用
valueForKey 替代getter方法
setValue:forKey 代替setter方法。
1.2)、常用方法
- (nullable id)valueForKey:(NSString *)key;
- (nullable id)valueForKeyPath:(NSString*)keyPath;
- (void)setValue:(nullable id)value forKey:(NSString *)key;
- (void)setValue:(nullable id)value forKeyPath:(NSString*)keyPath;
1.3)、使用场景
场景一:单层字典模型转化
[self.loginModel setValuesForKeysWithDictionary:resultDic];
场景二:(iOS黑魔法) 通过KVC拿到控件API未暴露的属性,自定义修改
例:通过KVC拿到UITextField的占位label,修改颜色
UILabel *placeholderLabel=[self.userTextField valueForKeyPath:@"placeholderLabel"];
placeholderLabel.textColor = [UIColor redColor];
场景三:valueForKeyPath多用途(它可以访问属性的属性)
1、使用valueForKeyPath可以获取数组中的最小值、最大值、平均值、求和
CGFloat sum = [[array valueForKeyPath:@"@sum.floatValue"] floatValue];
CGFloat avg = [[array valueForKeyPath:@"@avg.floatValue"] floatValue];
CGFloat max =[[array valueForKeyPath:@"@max.floatValue"] floatValue];
CGFloat min =[[array valueForKeyPath:@"@min.floatValue"] floatValue];
2、数组内部去重(distinctUnionOfObjects)
[dataArray valueForKeyPath:@"@distinctUnionOfObjects.self"]
3、数组合并(去重合并:distinctUnionOfArrays.self、直接合并:unionOfArrays.self)
NSArray *temp1 = @[@3, @2, @2, @1];
NSArray *temp2 = @[@3, @4, @5];
NSLog(@"\n%@",[@[temp1, temp2] valueForKeyPath:@"@distinctUnionOfArrays.self"]);
NSLog(@"\n%@",[@[temp1, temp2] valueForKeyPath:@"@unionOfArrays.self"]);
输出两个数组:( 5, 1, 2, 3, 4 ), ( 3, 2, 2, 1, 3, 4, 5 )。
4、大小写转换(uppercaseString)及 打印字符串长度同样适用(length)
NSArray *array = @[@"name", @"w", @"aa", @"jimsa"];
NSLog(@"%@", [array valueForKeyPath:@"uppercaseString"]);
打印:
(NAME,W,AA,JIMSA)
这里只挑几个介绍一下,下一步等你自己实践吧
二、Runtime
2.1)、简介
runtime是一套底层的C语言API,包含很多强大实用的C语言数据类型和C语言函数,平时我们编写的OC代码,底层都是基于runtime实现的。
作用:能动态产生、修改、删除一个类,一个成员变量,一个方法。
2.2)、常用方法
常用头文件:
#import <objc/runtime.h> 包含对类、成员变量、属性、方法的操作
#import <objc/message.h> 包含消息机制
常用方法:
class_copyIvarList() 返回一个指向类的成员变量数组的指针
class_copyPropertyList() 返回一个指向类的属性数组的指针
一般项目中使用:
利用遍历类的属性,来快速的进行归档操作。
将从后台返回的json数据进行字典模型转换。
2.3)、使用场景
- 打印所有成员变量
- (void)getMemberVariables
{
unsigned int count = 0;
//拷贝出所有的成员变量列表
Ivar *ivars = class_copyIvarList([UITextField class], &count);
for (int i = 0; i<count; i++)
{
// 取出成员变量
Ivar ivar = *(ivars + i);
// 打印成员变量名字
NSLog(@"%s", ivar_getName(ivar));
// 打印成员变量的数据类型
NSLog(@"%s", ivar_getTypeEncoding(ivar));
}
//释放
free(ivars);
}
打印结果:
KVC-RunTime[7226:235692] _textStorage
KVC-RunTime[7226:235692] @"_UICascadingTextStor
KVC-RunTime[7226:235692] _borderStyle
...
KVC-RunTime[7226:235692] _leftView
KVC-RunTime[7226:235692] @"UIView"
KVC-RunTime[7226:235692] _leftViewMode
KVC-RunTime[7226:235692] q
KVC-RunTime[7226:235692] _rightView
...
- 获取所有属性的类名
- (void)getSonClassIvar
{
unsigned int methCount = 0;
Method *meths = class_copyMethodList([UITextField class], &methCount);
for(int i = 0; i < methCount; i++)
{
Method meth = meths[i];
SEL sel = method_getName(meth);
const char *name = sel_getName(sel);
NSLog(@"%s", name);
}
free(meths);
打印结果
KVC-RunTime[7279:238641] bs_setPlaceholder:
KVC-RunTime[7279:238641] placeholderColor
KVC-RunTime[7279:238641] setPlaceholderColor:
...
KVC-RunTime[7279:238641] setDelegate:
KVC-RunTime[7279:238641] methodSignatureForSelector:
KVC-RunTime[7279:238641] forwardingTargetForSelector:
...
}
三、Demo实现
3.1)、运用KVC实现动图效果
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor grayColor];
UITextField *userTextField = [[UITextField alloc] initWithFrame:CGRectMake(30, 100, 375, 40)];
userTextField.placeholder = @"请输入账号";
userTextField.tag = 101;
[userTextField addTarget:self action:@selector(textEditBegin:) forControlEvents:UIControlEventEditingDidBegin];
[userTextField addTarget:self action:@selector(textEditEnd:) forControlEvents:UIControlEventEditingDidEnd];
[self.view addSubview:userTextField];
UITextField *passwordTextField = [[UITextField alloc] initWithFrame:CGRectMake(30, 200, 375, 40)];
passwordTextField.placeholder = @"请输入密码";
userTextField.tag = 102;
[passwordTextField addTarget:self action:@selector(textEditBegin:) forControlEvents:UIControlEventEditingDidBegin];
[passwordTextField addTarget:self action:@selector(textEditEnd:) forControlEvents:UIControlEventEditingDidEnd];
[self.view addSubview:passwordTextField];
}
- (void)textEditBegin:(UITextField *)textField
{
UILabel *label = [textField valueForKey:@"placeholderLabel"];
label.textColor = [UIColor redColor];
}
- (void)textEditEnd:(UITextField *)textField
{
UILabel *label = [textField valueForKey:@"placeholderLabel"];
label.textColor = [UIColor lightGrayColor];
}
3.2)、运用Runtime实现动图效果
新建一个UITextField类别:
UITextField+PlaceHoderColor.h
分类内部实现:
#import "UITextField+PlaceHoderColor.h"
#import <objc/runtime.h>
NSString * const placeholderColorName = @"placeholderColor";
@implementation UITextField (PlaceHoderColor)
// 需要给系统UITextField添加属性,只能使用runtime
- (void)setPlaceholderColor:(UIColor *)placeholderColor
{
// 设置关联
objc_setAssociatedObject(self,(__bridge const void *)(placeholderColorName), placeholderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// 设置占位文字颜色
UILabel *placeholderLabel = [self valueForKeyPath:@"placeholderLabel"];
placeholderLabel.textColor = placeholderColor;
}
//返回关联
- (UIColor *)placeholderColor
{
return objc_getAssociatedObject(self, (__bridge const void *)(placeholderColorName));
}
+ (void)load
{
//获取setPlaceholder
Method setPlaceholder = class_getInstanceMethod(self, @selector(setPlaceholder:));
//获取bs_setPlaceholder
Method bs_setPlaceholder = class_getInstanceMethod(self, @selector(bs_setPlaceholder:));
//交换方法
method_exchangeImplementations(setPlaceholder, bs_setPlaceholder);
}
// 设置占位文字,并且设置占位文字颜色
- (void)bs_setPlaceholder:(NSString *)placeholder
{
// 1.设置占位文字
[self bs_setPlaceholder:placeholder];
// 2.设置占位文字颜色
self.placeholderColor = self.placeholderColor;
}
@end
viewDidLoad于同3.1
调用分类方法:
- (void)textEditBegin:(UITextField *)textField
{
textField.placeholderColor = [UIColor redColor];
}
- (void)textEditEnd:(UITextField *)textField
{
textField.placeholderColor = [UIColor lightGrayColor];
}
参考:
Gavin_peng:iOS中的runtime应用
尼克name:iOS开发中和 valueForKeyPath 有关的一些简单数组操作
IOS_sunny:valueForKeyPath常用用法
小麦麦子: iOS开发学习之自定义UITextField详解