runTime常用用法

動(dòng)態(tài)給分類添加屬性

1.創(chuàng)建UIGestureRecognizer的類目 UIGestureRecognizer+Block.h

#import "UIGestureRecognizer+Block.h"
#import <objc/runtime.h>

static const int target_key;

@implementation UIGestureRecognizer (Block)

+ (instancetype) yj_gesterRrecognizerWithAction:(YJBlock)block
{
    __weak typeof(self) weakself = self;
    return [[weakself alloc] initWithActionBlock:block];
}

- (instancetype) initWithActionBlock:(YJBlock)block
{
    self = [self init];
    [self addActionBlock:block];
    [self addTarget:self action:@selector(invoke:)];
    return self;
}

- (void) invoke:(id)sender
{
    YJBlock block = objc_getAssociatedObject(self, &target_key);
    if (block){
        block(sender);
    }
}

- (void) addActionBlock:(YJBlock)block
{
    if (block){
        objc_setAssociatedObject(self, &target_key, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
}

 objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
  • id object 給誰添加就是誰的對(duì)象
  • const void *key 關(guān)聯(lián)對(duì)象的key
  • id value 被關(guān)聯(lián)者(要添加的屬性),這里是一個(gè)block()
  • objc_AssociationPolicy policy : 關(guān)聯(lián)時(shí)采用的協(xié)議偏塞,有assign筹燕,retain耙饰,copy等協(xié)議谬返,一般使用OBJC_ASSOCIATION_RETAIN_NONATOMIC
    2.在創(chuàng)建的類中進(jìn)行調(diào)用
UIView *viewM = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    viewM.backgroundColor = [UIColor grayColor];
    [self.view addSubview:viewM];
    [viewM addGestureRecognizer:[UITapGestureRecognizer yj_gesterRrecognizerWithAction:^(id gesterRecognizer) {
        NSLog(@"點(diǎn)擊了view");
    }]];

方法的交換

1.創(chuàng)建UIImage的類目UIImage+hook.h

#import "UIImage+hook.h"
#import <objc/runtime.h>
@implementation UIImage (hook)

+(void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class selfClass = object_getClass([self class]);
        SEL oriSEL = @selector(imageNamed:);
        Method oriMethod = class_getInstanceMethod(selfClass, oriSEL);
        
        SEL cusSEL = @selector(myImageNamed:);
        Method cusMethod = class_getInstanceMethod(selfClass, cusSEL);
        
        BOOL addSuccess = class_addMethod(selfClass, oriSEL, method_getImplementation(cusMethod), method_getTypeEncoding(cusMethod));
        if (addSuccess){
            class_replaceMethod(selfClass, cusSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
        }else{
            method_exchangeImplementations(oriMethod, cusMethod);
        }
        
    });
}

+(UIImage *)myImageNamed:(NSString *)name
{
    NSString *newName = [NSString stringWithFormat:@"%@%@",@"new_",name];
    return [self myImageNamed:newName];
}

@end

//替換方法

class_replaceMethod(<#Class  _Nullable __unsafe_unretained cls#>, <#SEL  _Nonnull name#>, <#IMP  _Nonnull imp#>, <#const char * _Nullable types#>)
  • 第一個(gè)參數(shù) class: 給哪個(gè)類添加參數(shù)
  • 第二個(gè)參數(shù) SEL : 被替換的那個(gè)方法
  • 第三個(gè)參數(shù) IMP : A function which is the implementation of the new method. The function must take at least two arguments—self and _cmd.
  • 第四個(gè)參數(shù) types :An array of characters that describe the types of the arguments to the method.
    2.調(diào)用
UIImageView *subView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    //圖片的實(shí)際名字是 new_Cart
    [subView setImage:[UIImage imageNamed:@"Cart"]];
    [self.view addSubview:subView];

字典轉(zhuǎn)模型

1.創(chuàng)建NSObjec的類別 NSObject+hook.h

#import "NSObject+hook.h"
#import <objc/runtime.h>
@implementation NSObject (hook)

const char *kPeropertyListKey = "kkkkkPeropertyListKey";

+ (instancetype) modelWithdict:(NSDictionary *)dict
{
    /* 實(shí)例化對(duì)象*/
    id objc = [[self alloc] init];
    /* 使用字典,設(shè)置對(duì)象信息*/
    /* 1.或者self的屬性列表*/
    NSArray *propertyList = [self yj_PropertyList];
    /* 2.遍歷字典*/
    [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        /* 3.判斷 key是否 propertyList中*/
        if ([propertyList containsObject:key]){
            /* 說明屬性存在,可以使用kvc 設(shè)置數(shù)值*/
            [objc setValue:obj forKey:key];
        }
    }];
    /*返回對(duì)象*/
    return objc;
}


- (NSArray *) yj_PropertyList
{
    NSArray *ptyList = objc_getAssociatedObject(self, kPeropertyListKey);
    /* 如果 ptyList有值,直接返回*/
    if (ptyList){
        return ptyList;
    }
    /* 調(diào)用運(yùn)行時(shí)方法, 取得類的屬性列表 */
    /* 成員變量:
     * class_copyIvarList(__unsafe_unretained Class cls, unsigned int *outCount)
     * 方法:
     * class_copyMethodList(__unsafe_unretained Class cls, unsigned int *outCount)
     * 屬性:
     * class_copyPropertyList(__unsafe_unretained Class cls, unsigned int *outCount)
     * 協(xié)議:
     * class_copyProtocolList(__unsafe_unretained Class cls, unsigned int *outCount)
     */
    unsigned int outCount = 0;
    /**
     * 參數(shù)1: 要獲取得類
     * 參數(shù)2: 類屬性的個(gè)數(shù)指針
     * 返回值: 所有屬性的數(shù)組, C 語言中,數(shù)組的名字,就是指向第一個(gè)元素的地址
     */
    /* retain, creat, copy 需要release */
    objc_property_t *properrtyList = class_copyPropertyList([self class], &outCount);
    NSMutableArray *mtArray = [NSMutableArray array];
    /* 遍歷所有屬性*/
    for (unsigned int i = 0; i < outCount; i++) {
        /* 從數(shù)組中取得屬性 */
        objc_property_t property = properrtyList[i];
        /* 從 property 中獲得屬性名稱 */
        const char *propertyName_C = property_getName(property);
        /* 將 C 字符串轉(zhuǎn)化成 OC 字符串 */
        NSString *propertyName_OC = [NSString stringWithCString:propertyName_C encoding:NSUTF8StringEncoding];
        [mtArray addObject:propertyName_OC];
    }
    /* 設(shè)置關(guān)聯(lián)對(duì)象 */
    /**
     *  參數(shù)1 : 對(duì)象self
     *  參數(shù)2 : 動(dòng)態(tài)添加屬性的 key
     *  參數(shù)3 : 動(dòng)態(tài)添加屬性值
     *  參數(shù)4 : 對(duì)象的引用關(guān)系
     */
    objc_setAssociatedObject(self, kPeropertyListKey, mtArray.copy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    /* 釋放 */
    free(properrtyList);
    return mtArray.copy;
}
@end

2.創(chuàng)建模型

#import <Foundation/Foundation.h>
#import "NSObject+hook.h"
@interface Model : NSObject

@property (copy,nonatomic) NSString *name;

@property (copy,nonatomic) NSString *sex;

@property (copy,nonatomic) NSString *age;

@end

3.調(diào)用

NSDictionary *dic = @{@"name":@"我愛NBA",
                          @"sex":@"男",
                          @"age":@25
                          };
    Model *model = [Model modelWithdict:dic];
    NSLog(@"name:%@  sex:%@  ",model.name,model.sex);
2018-02-28 09:50:32.343396+0800 RunTime使用場(chǎng)景[18298:1609962] name:我愛NBA  sex:男

對(duì)私有屬性進(jìn)行修改

#pragma mark - 獲取所有的屬性(包括私有的)
- (void) getAllIvar
{
    unsigned int count = 0;
    //Ivar: 定義對(duì)象的實(shí)例變量,包括類型和名字
    //獲取所有的屬性(包括私有的)
    Ivar *ivars = class_copyIvarList([NSString class], &count);
    for (int i = 0; i< count; i++) {
        //去除成員變量
        Ivar ivar = ivars[i];
        NSString *name = [NSString stringWithUTF8String:ivar_getName(ivar)];
        NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
        NSLog(@"屬性->%@ 和 %@",name,type);
    }
}

- (void) getAllMethod
{
    unsigned int count = 0;
    Method *methodList = class_copyMethodList([UIPageControl class], &count);
    for (int i = 0 ; i< count; i ++) {
        Method method = methodList[i];
        NSString *methodName = NSStringFromSelector(method_getName(method));
        NSLog(@"方法名 ->%@",methodName);
    }
}

歸檔解檔

1.創(chuàng)建YYModel

#import <Foundation/Foundation.h>

@interface YYModel : NSObject <NSCoding>

@property(nonatomic,assign) NSInteger age;
@property(nonatomic,copy) NSString *name1;
@property(nonatomic,copy) NSString *name2;
@property(nonatomic,copy) NSString *name3;
@property(nonatomic,copy) NSString *name4;
@property(nonatomic,copy) NSString *name5;

@end

------------------------------.m文件

#import "YYModel.h"
#import <objc/runtime.h>

@implementation YYModel
//NSKeyedUnarchiver 從二進(jìn)制流讀取對(duì)象姐叁。
//NSKeyedArchiver 把對(duì)象寫到二進(jìn)制流中去航背。


// 讀取實(shí)例變量铺董,并把這些數(shù)據(jù)寫到coder中去巫击。序列化數(shù)據(jù)
//1)禀晓、如果是類 就用encodeObject: forKey:
//2)、如果是普通的數(shù)據(jù)類型就用 eg坝锰、encodeInt: forKey:
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    unsigned int count = 0;
    //利用runtime獲取實(shí)例變量的列表
    Ivar *ivarList = class_copyIvarList([self class], &count);
    for (int i =0; i< count; i++) {
        //讀出i位置對(duì)應(yīng)的實(shí)例變量
        Ivar ivar =ivarList[i];
        //查看實(shí)例變量的名字
        const char *name = ivar_getName(ivar);
        //c語言字符串轉(zhuǎn)化為nsstring
        NSString *namestr = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
        //利用kvo取出屬性對(duì)應(yīng)的值
        id value = [self valueForKey:namestr];
        //歸檔
        [aCoder encodeObject:value forKey:namestr];
    }
    //記住c語言copy出來的要進(jìn)行釋放
    free(ivarList);
}

//從coder中讀取數(shù)據(jù)粹懒,保存到相應(yīng)的變量中,即反序列化數(shù)據(jù)
//1)顷级、如果是類 就用decodeObjectForKey:
//2)凫乖、如果是普通的數(shù)據(jù)類型就用 eg、decodeIntForKey:
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super init]) {
        unsigned int count = 0;
        Ivar *ivarList = class_copyIvarList([self class], &count);
        for (int i = 0 ; i< count; i++) {
            Ivar ivar = ivarList[i];
            const char *name = ivar_getName(ivar);
            NSString *namestr = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
            id value = [aDecoder decodeObjectForKey:namestr];
            //設(shè)置到成員變量身上
            [self setValue:value forKey:namestr];
        }
        free(ivarList);
    }
    return self;
}

@end

2.調(diào)用

YYModel *model = [[YYModel alloc] init];
    model.age = 18;
    model.name1 = @"胡航";
    model.name2 = @"梁靜茹";
    model.name3 = @"女女生";
    //創(chuàng)建路徑
    NSString *docunmentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
    NSLog(@"docunmentPath路徑:%@",docunmentPath);
    NSString *filePath = [docunmentPath stringByAppendingString:@"/YYModel.data"];
    //存儲(chǔ)用戶信息,歸檔
    BOOL result = [NSKeyedArchiver archiveRootObject:model toFile:filePath];
    if (result) {
        NSLog(@"歸檔成功%@",filePath);
    }else{
        NSLog(@"歸檔失敗");
    }
    
    
    YYModel *yy = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    NSLog(@"年齡%@\nname1:%@\nname2:%@",@(yy.age),yy.name1,yy.name2);

動(dòng)態(tài)添加方法

1.創(chuàng)建類dog

#import "Dog.h"
#import <objc/runtime.h>

@implementation Dog

// 默認(rèn)方法都有兩個(gè)隱式參數(shù)
void eat(id self,SEL sel){
    NSLog(@"%@ %@",self,NSStringFromSelector(sel));
    NSLog(@"動(dòng)態(tài)添加了一個(gè)方法");
}

//當(dāng)一個(gè)對(duì)象調(diào)用未實(shí)現(xiàn)的方法,會(huì)調(diào)用這個(gè)方法處理,并且會(huì)把對(duì)應(yīng)的方法列表傳過來
//剛好可以用來判斷,未實(shí)現(xiàn)的方法是不是我們想要添加動(dòng)態(tài)添加的方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    if (sel == NSSelectorFromString(@"eat")) {
        //注意:這里需要強(qiáng)轉(zhuǎn)成IMP類型
        class_addMethod(self, sel, (IMP)eat, "v@:");
        return YES;
    }
    //先恢復(fù),不然會(huì)覆蓋系統(tǒng)的方法
    return [super resolveInstanceMethod:sel];
}
@end

2.實(shí)現(xiàn)

Dog *dog = [[Dog alloc] init];
    //默認(rèn)dog,沒有實(shí)現(xiàn)eat方法,可以通過performSelector調(diào)用,但是會(huì)報(bào)錯(cuò)
    //動(dòng)態(tài)添加方法就不會(huì)報(bào)錯(cuò)
    [dog performSelector:@selector(eat)];

另附runtime用法demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末弓颈,一起剝皮案震驚了整個(gè)濱河市帽芽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌翔冀,老刑警劉巖导街,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異纤子,居然都是意外死亡菊匿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門计福,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人徽职,你說我怎么就攤上這事象颖。” “怎么了姆钉?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵说订,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我潮瓶,道長(zhǎng)陶冷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任毯辅,我火速辦了婚禮埂伦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘思恐。我一直安慰自己沾谜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布胀莹。 她就那樣靜靜地躺著基跑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪描焰。 梳的紋絲不亂的頭發(fā)上媳否,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼篱竭。 笑死力图,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的室抽。 我是一名探鬼主播搪哪,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼坪圾!你這毒婦竟也來了晓折?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤兽泄,失蹤者是張志新(化名)和其女友劉穎漓概,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體病梢,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胃珍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蜓陌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片觅彰。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖钮热,靈堂內(nèi)的尸體忽然破棺而出傲须,到底是詐尸還是另有隱情藕赞,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站梦抢,受9級(jí)特大地震影響恬吕,放射性物質(zhì)發(fā)生泄漏检盼。R本人自食惡果不足惜儿咱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望性置。 院中可真熱鬧拾并,春花似錦、人聲如沸鹏浅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽篡石。三九已至芥喇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間凰萨,已是汗流浹背继控。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工械馆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人武通。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓霹崎,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親冶忱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子尾菇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,682評(píng)論 0 9
  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi閱讀 7,294評(píng)論 0 10
  • runtime 和 runloop 作為一個(gè)程序員進(jìn)階是必須的囚枪,也是非常重要的派诬, 在面試過程中是經(jīng)常會(huì)被問到的, ...
    made_China閱讀 1,202評(píng)論 0 7
  • runtime 和 runloop 作為一個(gè)程序員進(jìn)階是必須的链沼,也是非常重要的默赂, 在面試過程中是經(jīng)常會(huì)被問到的, ...
    SOI閱讀 21,780評(píng)論 3 63
  • 今天我為什么會(huì)難過呢 我以為我對(duì)別人好別人也會(huì)對(duì)我好呢括勺,事實(shí)上人家根本就不在乎你缆八。 我一直在心里問自己,如果那天換...
    小騰騰閱讀 222評(píng)論 0 0