为了账号安全,请及时绑定邮箱和手机立即绑定

iOS总结笔记 -- RunTime的用法

标签:
iOS

1.为系统类添加属性


#import <UIKit/UIKit.h>
#import <objc/runtime.h>

@interface UIButton (Level)

@property (nonatomic, copy)NSString* level;

@end
import "UIButton+Level.h"

static NSString *key = @"key";///这里只是一个Key标示

@implementation UIButton (Level)

-(void)setLevel:(NSString *)level
{
    objc_setAssociatedObject(self, &key,level, OBJC_ASSOCIATION_ASSIGN);

}

-(NSString *)level
{
  return  objc_getAssociatedObject(self, &key);
}
@end

 ////给Category添加属性
    ////先为扩展类声明需要添加的属性
    ///char runTime
    /// objc_getAssociatedObject///设置getter
    ///objc_setAssociatedObject///设置setter

 UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    btn.level = @"4级";
    NSLog(@"================%@",btn.level);

2.更改成员变量的值

///动态的更改成员变量的值
- (void)changeInstanceVolume
{
    //① 动态获取Car类中的所有属性[当然包括私有]
    unsigned int count = 0;
    Ivar *ivar = class_copyIvarList([self.car class], &count);
    //②遍历属性找到对应name字段
    for (int i = 0; i < count; i ++) {
        Ivar var = ivar[i];
        const char *varName = ivar_getName(var);
        NSString *name = [NSString stringWithUTF8String:varName];
        //③修改对应的字段值成age
        if ([name isEqualToString:@"_name"]) {
            object_setIvar(self.car, var, @"劳斯拉斯");
        }
    }
    NSLog(@"%@",self.car.name);
}

3.字典转model

+ (instancetype)modelWithDict:(NSDictionary *)dict{
    id model = [[self alloc] init];
    unsigned int count = 0;

    Ivar *ivars = class_copyIvarList(self, &count);
    for (int i = 0 ; i < count; i++) {
        Ivar ivar = ivars[i];

        NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];

        //这里注意,拿到的成员变量名为_cid,_age
        ivarName = [ivarName substringFromIndex:1];
        id value = dict[ivarName];

        [model setValue:value forKeyPath:ivarName];
    }

    return model;
}

4.消息转发相关

#import <Foundation/Foundation.h>

@interface Person : NSObject

- (void)run;

@end
#import "Person.h"
#include <objc/runtime.h>
#import "Car.h"

@implementation Person

///动态加载方法,当person对象调用run方法的时候,这时候重新写个方法添加里面

void runNew(id self, SEL cmd){
    NSLog(@"================");
}

//  第一步,消息接收者没有找到对应的方法时候,会先调用此方法,可在此方法实现中动态添加新的方法
//  返回YES表示相应selector的实现已经被找到,或者添加新方法到了类中,否则返回NO
+ (BOOL)resolveInstanceMethod:(SEL)sel {

//    if (sel == @selector(run)) {
//        class_addMethod(self, sel, (IMP)runNew, "v@:");
//        return YES;
//    }
//    return [super resolveInstanceMethod:sel];

    return YES;
}

//  第二步, 如果第一步的返回NO或者直接返回了YES而没有添加方法,该方法被调用
//  在这个方法中,我们可以指定一个可以返回一个可以响应该方法的对象, 注意如果返回self就会死循环,这里返回的对象就是要转移寻找的列表,换成到Car类里面寻找run方法的实现
- (id)forwardingTargetForSelector:(SEL)aSelector {
//    Car *car = [[Car alloc]init];
//    return car;
    return  nil;
}
//  第三步, 如果forwardingTargetForSelector:返回了nil,则该方法会被调用,系统会询问我们要一个合法的『类型编码(Type Encoding)』也就是方法签名
//  若返回 nil,则不会进入下一步,而是无法处理消息
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
//    return nil;
}

// 当实现了此方法后,-doesNotRecognizeSelector: 将不会被调用
// 在这里进行消息转发
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    // 在这里可以改变方法选择器
    [anInvocation setSelector:@selector(unknown)];
    // 改变方法选择器后,需要指定消息的接收者
    [anInvocation invokeWithTarget:self];
}

- (void)unknown {
    NSLog(@"unkown method.......");
}

// 如果没有实现消息转发 forwardInvocation  则调用此方法
- (void)doesNotRecognizeSelector:(SEL)aSelector {
//    NSLog(@"unresolved method :%@", NSStringFromSelector(aSelector));
}

@end
点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
32
获赞与收藏
322

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消