runtime获取属性列表,修改属性值,添加并修改私有方法的调用

用了两天好好的研究了一下runtime,之前初涉runtime。懵懵懂懂的了解runtime的强大,但是如何的强大,只是在demo中引用MJExtension的时候自动生成model,了解了一些。
经过一天半的研究,首先温习了之前的获取属性列表。

今天想说的具体功能如题所述。主要涉及的就是获取并修改属性。添加并修改私有方法。

好了,首先说一下如何获取属性值。如果需要获取某个属性,我们最先需要知道你想获取的类的名字。如果我们只有某一个类的字符串,同样可以达到目的,这也就是runtime的神奇之处。

(1)例如我们想要得到UserInfo这个类下的所有属性。但是现在只有字符串className=@"UserInfo",我们可以用最常见的runtime语句去获取到class。如下:Class UserInfo = NSClassFromString(className);这时候我们就得到了这个类。但是这时的UserInfo相当于没有alloc的类。

(2)我们在网上有两种方式可以获取到属性的name,type以及value。第一种方式如下:

- (NSArray*)getAllPropertyName//runtime获取model所有属性
{
    NSMutableArray* nameArray = [NSMutableArray array];
    unsigned int count = 0;
    objc_property_t *property_t = class_copyPropertyList([UserInfo class], &count);
    for (int i=0; i<count; i++) {
        objc_property_t propert = property_t[i];
        const char * propertyName = property_getName(propert);
        [nameArray addObject:[NSString stringWithUTF8String:propertyName]];
    }
    free(property_t);
    return nameArray;
}

上面只是获取到属性名,如果想要获取其它的东西,也可以自行查询方法。不过目前只有这个有点用。
第二种方法如下:

    unsigned int countNum = 0;
    Ivar *members = class_copyIvarList([self.panoramView class], &countNum);
    for (int i=0; i<countNum; i++) {
        Ivar var = members[i];
        const char *memberName = ivar_getName(var);
        //属性描述
        NSString *memberStr = [NSString stringWithFormat:@"%s",memberName];
        if ([memberStr isEqualToString:@"_advsObject"]) {
            const char * type = ivar_getTypeEncoding(var);
        }
    }

上面的方法获取到的属性是C的格式,需要转变成OC,所以中间写了一个memberStr作为媒介。

以上就是获取属性的方法,下面说下如何修改属性内容。

(3)其实修改属性的方法,很简单,就一句话,一共有三个参数。object_setIvar(id obj, Ivar ivar, id value)
*@param obj The object containing the instance variable whose value you want to set.
* @param ivar The Ivar describing the instance variable whose value you want to set.
* @param value The new value for the instance variable.*这是官方给的解释。

我们根据以上的三个参数,对其进行赋值,如下:object_setIvar(self.userInfo, var, @"改过的内容");
到此:属性的修改就结束了。今天写这篇文章,主要是为了记录如何修改私有方法的。所以接下来才是重头戏。

如果我们要修改某一个类库的私有方法,当然,通过runtime都是为了修改私有方法的,毕竟非私有方法,又何必用runtime这个繁琐的东西呢。我这里的需求说起来还是被第三方深恶痛绝的,但是对一些技术还处在一个瓶颈,无法越过的同学们是一个福音。
我的需求就是,下载的第三方,为了防止我们滥用他们的劳动成果,也或者为了获得一定的报酬,所以才在代码中封装一个明显的lable或者context等控件悬浮在view上。我就是要把他悬浮的这个控件屏蔽掉,或者隐藏或者remove掉,期初想用KVO,直接setvalue:hidden的,但是由于这个控件是私有变量,所以无法直接使用KVO访问的。最终选择了使用runtime修改私有方法即可。

(4)同样我们需要知道要修改的类的名字,然后获取该类下的所有方法。代码如下:

-(NSArray *)getAllMethods
{
    unsigned int count_f =0;
    //获取方法链表
    Method* methodList_f = class_copyMethodList([UserInfo class],&count_f);

    NSMutableArray *methodsArray = [NSMutableArray arrayWithCapacity:count_f];

    for(int i=0;i<count_f;i++)
    {
        Method temp_f = methodList_f[i];
        //方法的调用地址
        IMP imp_f = method_getImplementation(temp_f);
        //方法
        SEL name_f = method_getName(temp_f);
        //方法名字符串
        const char* name_s =sel_getName(method_getName(temp_f));
        //参数数量
        int arguments = method_getNumberOfArguments(temp_f);
        //返回方法的参数和返回值的描述的字串
        const char* encoding =method_getTypeEncoding(temp_f);
        NSLog(@"方法名:%@,参数个数:%d,编码方式:%@",[NSString stringWithUTF8String:name_s],
              arguments,[NSString stringWithUTF8String:encoding]);

        NSString *methodStr = NSStringFromSelector(name_f);

        [methodsArray addObject:methodStr];

    }
    free(methodList_f);

    return methodsArray;
}

以上就是获取的该类下的所有方法,这个时候我们就该猜了,这是一个痛苦的过程,因为我们不知道到底哪个方法是我们需要修改的。但是一般开发者命名的时候是会根据需要做的意思而命名的,我们只能这样缩小范围了,但是如果真的碰到了加密的方法,或者说命名方法没有规律的,那我真的没办法了。只能一个一个试试了。

(5)如果我们搜索到了方法名为:setUserName:我们需要添加方法,然后再修改这个私有方法的回调。

-(void)laodNewMethod
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [UserInfo class];
        //原来的方法
        SEL originalSelector = @selector(setUserName:);
        //新方法
        SEL swizzledSelector = @selector(setNewUserName:);
        //原来的Method
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        //新Method
        Method swizzledMethod = class_getInstanceMethod([self class], swizzledSelector);
        //添加到runtime新方法
        BOOL didAddMethod =class_addMethod(class,originalSelector,method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod));
        if (didAddMethod) {
            class_replaceMethod([self class],swizzledSelector,method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }


    });
}
-(void)setNewUserName:(NSString *)newUserName
{
    NSlog("这里就是修改后的方法,每次运行都会自动跳到这里调用这个方法了。")
}

以上就是所有今天关于runtime的内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值