通过实例了解KVC 、 Runtime

这个例子是我在网上看到的,主要介绍了用KVC和Runtime更改UITextField默认提示文字(PlaceHolder)颜色,借此机会简单介绍一下KVC和Runtime。附Demo地址:(点击我,免积分哦)

874828-519b69d9089bf83c.gif

目录:

  • 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详解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,019评论 4 62
  • KVC(Key-value coding)键值编码,单看这个名字可能不太好理解。其实翻译一下就很简单了,就是指iO...
    朽木自雕也阅读 1,548评论 6 1
  • 因为爱吃甜食所以亲吻你因为不爱吃醋所以拥抱你你看我们的关系不是人心隔肚皮
    木卯丁阅读 291评论 1 3