国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

Runtime的介紹與簡(jiǎn)單運(yùn)用(二)

2019-11-09 18:11:53
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

        在上一篇文章我們介紹了Runtime里面關(guān)于對(duì)象運(yùn)行在Runtime里面的表示,本篇文章我們講介紹關(guān)于Runtime在實(shí)際中的運(yùn)用

一、首先我們先談一下OC類(lèi)對(duì)象方法與類(lèi)方法調(diào)用的機(jī)制

如果用對(duì)象調(diào)方法,會(huì)到對(duì)象的isa指針指向的對(duì)象(也就是類(lèi)對(duì)象)操作。如果調(diào)用的是類(lèi)方法,就會(huì)到類(lèi)對(duì)象的isa指針指向的對(duì)象(也就是元類(lèi)對(duì)象)中操作。此處關(guān)于類(lèi)對(duì)象與元類(lèi)對(duì)象的區(qū)別我們將在后面介紹道首先,在相應(yīng)操作的對(duì)象中的緩存方法列表中找調(diào)用的方法,如果找到,轉(zhuǎn)向相應(yīng)實(shí)現(xiàn)并執(zhí)行。如果沒(méi)找到,在相應(yīng)操作的對(duì)象中的方法列表中找調(diào)用的方法,如果找到,轉(zhuǎn)向相應(yīng)實(shí)現(xiàn)執(zhí)行如果沒(méi)找到,去父類(lèi)指針?biāo)赶虻膶?duì)象中執(zhí)行1,2.以此類(lèi)推,如果一直到根類(lèi)還沒(méi)找到,轉(zhuǎn)向攔截調(diào)用。如果沒(méi)有重寫(xiě)攔截調(diào)用的方法,程序報(bào)錯(cuò)。以上的過(guò)程給我?guī)?lái)的啟發(fā):重寫(xiě)父類(lèi)的方法,并沒(méi)有覆蓋掉父類(lèi)的方法,只是在當(dāng)前類(lèi)對(duì)象中找到了這個(gè)方法后就不會(huì)再去父類(lèi)中找了。如果想調(diào)用已經(jīng)重寫(xiě)過(guò)的方法的父類(lèi)的實(shí)現(xiàn),只需使用super這個(gè)編譯器標(biāo)識(shí),它會(huì)在運(yùn)行時(shí)跳過(guò)在當(dāng)前的類(lèi)對(duì)象中尋找方法的過(guò)程。攔截調(diào)用在方法調(diào)用中說(shuō)到了,如果沒(méi)有找到方法就會(huì)轉(zhuǎn)向攔截調(diào)用。那么什么是攔截調(diào)用呢。攔截調(diào)用就是,在找不到調(diào)用的方法程序崩潰之前,我們通過(guò)重寫(xiě)NSObject的四個(gè)方法來(lái)處理。
/**此的方法是當(dāng)你調(diào)用一個(gè)不存在的類(lèi)方法的時(shí)候,會(huì)調(diào)用這個(gè)方法,默認(rèn)返回NO,你可以加上自己的處理然后返回YES。 */+ (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);/**此方法和上面的方法一樣,只是處理的是對(duì)象方法。 */+ (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
/**此方法是將你調(diào)用的不存在的方法重定向到一個(gè)其他聲明了這個(gè)方法的類(lèi),只需要你返回一個(gè)有這個(gè)方法的target。 */- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);/**此方法是將你調(diào)用的不存在的方法打包成NSInvocation傳給你。做完你自己的處理后,調(diào)用invokeWithTarget:方法讓某個(gè)target觸發(fā)這個(gè)方法。 */- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");

二、方法攔截添加運(yùn)用

首先我們創(chuàng)建一個(gè)測(cè)試類(lèi)TestClass,然后后調(diào)用一個(gè)該類(lèi)里面沒(méi)有的對(duì)象方法
    _testClass = [TestClass new];    [_testClass performSelector:@selector(testMethod:) withObject:@"test"]; 正常情況下程序會(huì)崩潰,因?yàn)樵擃?lèi)沒(méi)有此方法,父類(lèi)也沒(méi)有,我們也沒(méi)有做相應(yīng)處理,日志如下
2017-02-07 10:53:42.318 RuntimeDemo[1809:61956] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TestClass testMethod:]: unrecognized selector sent to instance 0x6080000021d0' 如果我們重寫(xiě)resolveInstanceMethod并在方法里面增加該方法,那面程序就會(huì)運(yùn)行通過(guò),
void runAddMethod(id self, SEL _cmd, NSString *string){    NSLog(@"add C IMP %@", string);}+ (BOOL)resolveInstanceMethod:(SEL)sel{    //給本類(lèi)動(dòng)態(tài)添加一個(gè)方法    if ([NSStringFromSelector(sel) isEqualToString:@"testMethod:"]) {        class_addMethod(self, sel, (IMP)runAddMethod, "v@:*");    }    return YES;}

其中class_addMethod的四個(gè)參數(shù)分別是:

Class cls 給哪個(gè)類(lèi)添加方法,本例中是selfSEL name 添加的方法,本例中是重寫(xiě)的攔截調(diào)用傳進(jìn)來(lái)的selector。IMP imp 方法的實(shí)現(xiàn),C方法的方法實(shí)現(xiàn)可以直接獲得。如果是OC方法,可以用+ (IMP)instanceMethodForSelector:(SEL)aSelector;獲得方法的實(shí)現(xiàn)。"v@:*"方法的簽名,代表有一個(gè)參數(shù)的方法。

三、關(guān)聯(lián)對(duì)象

        假如正在使用一個(gè)系統(tǒng)的類(lèi)并不能滿足你的需求,你需要額外添加一個(gè)屬性。這種情況的一般解決辦法就是繼承。但是,只增加一個(gè)屬性,就去繼承一個(gè)類(lèi),總是覺(jué)得太麻煩類(lèi)。這個(gè)時(shí)候,runtime的關(guān)聯(lián)屬性就發(fā)揮它的作用了。
//首先定義一個(gè)全局變量,用它的地址作為關(guān)聯(lián)對(duì)象的keystatic char associatedObjectKey;//設(shè)置關(guān)聯(lián)對(duì)象objc_setAssociatedObject(target, &associatedObjectKey, @"添加的字符串屬性", OBJC_ASSOCIATION_RETAIN_NONATOMIC); //獲取關(guān)聯(lián)對(duì)象NSString *string = objc_getAssociatedObject(target, &associatedObjectKey);NSLog(@"AssociatedObject = %@", string);objc_setAssociatedObject的四個(gè)參數(shù):id object給誰(shuí)設(shè)置關(guān)聯(lián)對(duì)象。const void *key關(guān)聯(lián)對(duì)象唯一的key,獲取時(shí)會(huì)用到。id value關(guān)聯(lián)對(duì)象。objc_AssociationPolicy關(guān)聯(lián)策略,有以下幾種策略:enum {    OBJC_ASSOCIATION_ASSIGN = 0,    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,    OBJC_ASSOCIATION_RETAIN = 01401,    OBJC_ASSOCIATION_COPY = 01403};如果你熟悉OC,看名字應(yīng)該知道這幾種策略就是屬性修飾關(guān)鍵字。objc_getAssociatedObject的兩個(gè)參數(shù)。id object獲取誰(shuí)的關(guān)聯(lián)對(duì)象。const void *key根據(jù)這個(gè)唯一的key獲取關(guān)聯(lián)對(duì)象。其實(shí),你還可以把添加和獲取關(guān)聯(lián)對(duì)象的方法寫(xiě)在你需要用到這個(gè)功能的類(lèi)的類(lèi)別中,方便使用。
//添加關(guān)聯(lián)對(duì)象- (void)addAssociatedObject:(id)object{    objc_setAssociatedObject(self, @selector(getAssociatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}//獲取關(guān)聯(lián)對(duì)象- (id)getAssociatedObject{    return objc_getAssociatedObject(self, _cmd);}注意:這里面我們把getAssociatedObject方法的地址作為唯一的key,_cmd代表當(dāng)前調(diào)用方法的地址。

三、方法交換

方法交換,顧名思義,就是將兩個(gè)方法的實(shí)現(xiàn)交換。例如,將A方法和B方法交換,調(diào)用A方法的時(shí)候,就會(huì)執(zhí)行B方法中的代碼,反之亦然。
#import "UIViewController+swizzling.h"#import <objc/runtime.h>@implementation UIViewController (swizzling)//load方法會(huì)在類(lèi)第一次加載的時(shí)候被調(diào)用//調(diào)用的時(shí)間比較靠前,適合在這個(gè)方法里做方法交換+ (void)load{    //方法交換應(yīng)該被保證,在程序中只會(huì)執(zhí)行一次    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        //獲得viewController的生命周期方法的selector        SEL systemSel = @selector(viewWillAppear:);        //自己實(shí)現(xiàn)的將要被交換的方法的selector        SEL swizzSel = @selector(swiz_viewWillAppear:);        //兩個(gè)方法的Method        Method systemMethod = class_getInstanceMethod([self class], systemSel);        Method swizzMethod = class_getInstanceMethod([self class], swizzSel);        //首先動(dòng)態(tài)添加方法,實(shí)現(xiàn)是被交換的方法,返回值表示添加成功還是失敗        BOOL isAdd = class_addMethod(self, systemSel, method_getImplementation(swizzMethod), method_getTypeEncoding(swizzMethod));        if (isAdd) {            //如果成功,說(shuō)明類(lèi)中不存在這個(gè)方法的實(shí)現(xiàn)            //將被交換方法的實(shí)現(xiàn)替換到這個(gè)并不存在的實(shí)現(xiàn)            class_replaceMethod(self, swizzSel, method_getImplementation(systemMethod), method_getTypeEncoding(systemMethod));        }else{            //否則,交換兩個(gè)方法的實(shí)現(xiàn)            method_exchangeImplementations(systemMethod, swizzMethod);        }    });}- (void)swiz_viewWillAppear:(BOOL)animated{    //這時(shí)候調(diào)用自己,看起來(lái)像是死循環(huán)    //但是其實(shí)自己的實(shí)現(xiàn)已經(jīng)被替換了    [self swiz_viewWillAppear:animated];    NSLog(@"swizzle");}@end在一個(gè)自己定義的viewController中重寫(xiě)viewWillAppear
- (void)viewWillAppear:(BOOL)animated{    [super viewWillAppear:animated];    NSLog(@"viewWillAppear");}
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 岗巴县| 赣州市| 兴仁县| 西乡县| 乐业县| 汉川市| 商河县| 衡东县| 甘肃省| 杭州市| 安阳市| 吉首市| 那坡县| 闸北区| 宁明县| 平遥县| 上高县| 新绛县| 垣曲县| 浦城县| 基隆市| 修武县| 太原市| 遵义市| 邢台市| 宿松县| 柘城县| 安义县| 苍山县| 诏安县| 梨树县| 石河子市| 平遥县| 镇雄县| 澄迈县| 通化县| 台安县| 东平县| 仙游县| 上高县| 大洼县|