通過實(shí)例了解KVC 、 Runtime

這個(gè)例子是我在網(wǎng)上看到的,主要介紹了用KVC和Runtime更改UITextField默認(rèn)提示文字(PlaceHolder)顏色,借此機(jī)會(huì)簡(jiǎn)單介紹一下KVC和Runtime。附Demo地址:(點(diǎn)擊我,免積分哦)

874828-519b69d9089bf83c.gif

目錄:

  • KVC
    概念
    常用方法
    常用場(chǎng)景
  • Runtime
    概念
    常用方法
    使用場(chǎng)景
  • Demo實(shí)現(xiàn)
    運(yùn)用KVC實(shí)現(xiàn)動(dòng)圖效果
    運(yùn)用Runtime實(shí)現(xiàn)動(dòng)圖效果

一、KVC (Key-value coding)鍵值編碼

1.1)、簡(jiǎn)介

通過Key名直接訪問對(duì)象的屬性,或者給對(duì)象的屬性賦值,而不需要調(diào)用明確的存取方法。這樣就可以在運(yùn)行,時(shí)動(dòng)態(tài)在訪問和修改對(duì)象的屬性。而不是在編譯時(shí)確定,這也是iOS開發(fā)中的黑魔法之一。

通常我們使用
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)、使用場(chǎng)景

場(chǎng)景一:?jiǎn)螌幼值淠P娃D(zhuǎn)化

[self.loginModel setValuesForKeysWithDictionary:resultDic];

場(chǎng)景二:(iOS黑魔法) 通過KVC拿到控件API未暴露的屬性,自定義修改

例:通過KVC拿到UITextField的占位label,修改顏色

UILabel *placeholderLabel=[self.userTextField valueForKeyPath:@"placeholderLabel"];
placeholderLabel.textColor = [UIColor redColor];

場(chǎng)景三:valueForKeyPath多用途(它可以訪問屬性的屬性)

1、使用valueForKeyPath可以獲取數(shù)組中的最小值、最大值、平均值、求和

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、數(shù)組內(nèi)部去重(distinctUnionOfObjects)

[dataArray valueForKeyPath:@"@distinctUnionOfObjects.self"]
3、數(shù)組合并(去重合并: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"]);

輸出兩個(gè)數(shù)組:( 5, 1, 2, 3, 4 ), ( 3, 2, 2, 1, 3, 4, 5 )。
4、大小寫轉(zhuǎn)換(uppercaseString)及 打印字符串長(zhǎng)度同樣適用(length)

NSArray *array = @[@"name", @"w", @"aa", @"jimsa"];
NSLog(@"%@", [array valueForKeyPath:@"uppercaseString"]);
打印:
(NAME,W,AA,JIMSA)

這里只挑幾個(gè)介紹一下,下一步等你自己實(shí)踐吧

二、Runtime

2.1)、簡(jiǎn)介

runtime是一套底層的C語言API,包含很多強(qiáng)大實(shí)用的C語言數(shù)據(jù)類型和C語言函數(shù),平時(shí)我們編寫的OC代碼,底層都是基于runtime實(shí)現(xiàn)的。
作用:能動(dòng)態(tài)產(chǎn)生、修改、刪除一個(gè)類,一個(gè)成員變量,一個(gè)方法。

2.2)、常用方法

常用頭文件:
#import <objc/runtime.h> 包含對(duì)類、成員變量、屬性、方法的操作
#import <objc/message.h> 包含消息機(jī)制

常用方法:
class_copyIvarList()     返回一個(gè)指向類的成員變量數(shù)組的指針
class_copyPropertyList() 返回一個(gè)指向類的屬性數(shù)組的指針

一般項(xiàng)目中使用:
利用遍歷類的屬性,來快速的進(jìn)行歸檔操作。
將從后臺(tái)返回的json數(shù)據(jù)進(jìn)行字典模型轉(zhuǎn)換。

2.3)、使用場(chǎng)景

  • 打印所有成員變量
- (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));
        // 打印成員變量的數(shù)據(jù)類型
        NSLog(@"%s", ivar_getTypeEncoding(ivar));
    }
    //釋放
    free(ivars);
}


打印結(jié)果:
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);


打印結(jié)果
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實(shí)現(xiàn)

3.1)、運(yùn)用KVC實(shí)現(xiàn)動(dòng)圖效果

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor grayColor];
    
    UITextField *userTextField = [[UITextField alloc] initWithFrame:CGRectMake(30, 100, 375, 40)];
    userTextField.placeholder = @"請(qǐng)輸入賬號(hào)";
    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 = @"請(qǐng)輸入密碼";
    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)、運(yùn)用Runtime實(shí)現(xiàn)動(dòng)圖效果

新建一個(gè)UITextField類別:

UITextField+PlaceHoderColor.h
分類內(nèi)部實(shí)現(xiàn):

#import "UITextField+PlaceHoderColor.h"
#import <objc/runtime.h>

NSString * const placeholderColorName = @"placeholderColor";

@implementation UITextField (PlaceHoderColor)

// 需要給系統(tǒng)UITextField添加屬性,只能使用runtime
- (void)setPlaceholderColor:(UIColor *)placeholderColor
{
    // 設(shè)置關(guān)聯(lián)
    objc_setAssociatedObject(self,(__bridge const void *)(placeholderColorName), placeholderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    // 設(shè)置占位文字顏色
    UILabel *placeholderLabel = [self valueForKeyPath:@"placeholderLabel"];
    placeholderLabel.textColor = placeholderColor;
}

//返回關(guān)聯(lián)
- (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);
}

// 設(shè)置占位文字,并且設(shè)置占位文字顏色
- (void)bs_setPlaceholder:(NSString *)placeholder
{
    // 1.設(shè)置占位文字
    [self bs_setPlaceholder:placeholder];
    // 2.設(shè)置占位文字顏色
    self.placeholderColor = self.placeholderColor;
}
@end

viewDidLoad于同3.1

調(diào)用分類方法:
- (void)textEditBegin:(UITextField *)textField
{
    textField.placeholderColor = [UIColor redColor];
}

- (void)textEditEnd:(UITextField *)textField
{
    textField.placeholderColor = [UIColor lightGrayColor];
}

參考:

Gavin_peng:iOS中的runtime應(yīng)用
尼克name:iOS開發(fā)中和 valueForKeyPath 有關(guān)的一些簡(jiǎn)單數(shù)組操作
IOS_sunny:valueForKeyPath常用用法
小麥麥子: iOS開發(fā)學(xué)習(xí)之自定義UITextField詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,353評(píng)論 4 61
  • KVC(Key-value coding)鍵值編碼,單看這個(gè)名字可能不太好理解。其實(shí)翻譯一下就很簡(jiǎn)單了,就是指iO...
    朽木自雕也閱讀 1,700評(píng)論 6 1
  • 因?yàn)閻鄢蕴鹗乘杂H吻你因?yàn)椴粣鄢源姿該肀隳憧次覀兊年P(guān)系不是人心隔肚皮
    攝影師柳丁閱讀 321評(píng)論 1 3

友情鏈接更多精彩內(nèi)容