查看: 618|回复: 0

[IOS开发教程] iOS总结笔记 -- RunTime的用法

发表于 2018-1-29 08:00:02
1.为系统类添加属性
  1. #import <UIKit/UIKit.h>
  2. #import <objc/runtime.h>
  3. @interface UIButton (Level)
  4. @property (nonatomic, copy)NSString* level;
  5. @end
复制代码
  1. import "UIButton+Level.h"
  2. static NSString *key = @"key";//这里只是一个Key标示
  3. @implementation UIButton (Level)
  4. -(void)setLevel:(NSString *)level
  5. {
  6. objc_setAssociatedObject(self, &key,level, OBJC_ASSOCIATION_ASSIGN);
  7. }
  8. -(NSString *)level
  9. {
  10. return objc_getAssociatedObject(self, &key);
  11. }
  12. @end
复制代码
  1. ///给Category添加属性
  2. ///先为扩展类声明需要添加的属性
  3. //char runTime
  4. // objc_getAssociatedObject//设置getter
  5. //objc_setAssociatedObject//设置setter
  6. UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
  7. btn.level = @"4级";
  8. NSLog(@"================%@",btn.level);
复制代码
2.更改成员变量的值
  1. //动态的更改成员变量的值
  2. - (void)changeInstanceVolume
  3. {
  4. //① 动态获取Car类中的所有属性[当然包括私有]
  5. unsigned int count = 0;
  6. Ivar *ivar = class_copyIvarList([self.car class], &count);
  7. //②遍历属性找到对应name字段
  8. for (int i = 0; i < count; i ++) {
  9. Ivar var = ivar[i];
  10. const char *varName = ivar_getName(var);
  11. NSString *name = [NSString stringWithUTF8String:varName];
  12. //③修改对应的字段值成age
  13. if ([name isEqualToString:@"_name"]) {
  14. object_setIvar(self.car, var, @"劳斯拉斯");
  15. }
  16. }
  17. NSLog(@"%@",self.car.name);
  18. }
复制代码
3.字典转model
  1. + (instancetype)modelWithDict:(NSDictionary *)dict{
  2. id model = [[self alloc] init];
  3. unsigned int count = 0;
  4. Ivar *ivars = class_copyIvarList(self, &count);
  5. for (int i = 0 ; i < count; i++) {
  6. Ivar ivar = ivars[i];
  7. NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
  8. //这里注意,拿到的成员变量名为_cid,_age
  9. ivarName = [ivarName substringFromIndex:1];
  10. id value = dict[ivarName];
  11. [model setValue:value forKeyPath:ivarName];
  12. }
  13. return model;
  14. }
复制代码
4.消息转发相关
  1. #import <Foundation/Foundation.h>
  2. @interface Person : NSObject
  3. - (void)run;
  4. @end
复制代码
  1. #import "Person.h"
  2. #include <objc/runtime.h>
  3. #import "Car.h"
  4. @implementation Person
  5. //动态加载方法,当person对象调用run方法的时候,这时候重新写个方法添加里面
  6. void runNew(id self, SEL cmd){
  7. NSLog(@"================");
  8. }
  9. // 第一步,消息接收者没有找到对应的方法时候,会先调用此方法,可在此方法实现中动态添加新的方法
  10. // 返回YES表示相应selector的实现已经被找到,或者添加新方法到了类中,否则返回NO
  11. + (BOOL)resolveInstanceMethod:(SEL)sel {
  12. // if (sel == @selector(run)) {
  13. // class_addMethod(self, sel, (IMP)runNew, "v@:");
  14. // return YES;
  15. // }
  16. // return [super resolveInstanceMethod:sel];
  17. return YES;
  18. }
  19. // 第二步, 如果第一步的返回NO或者直接返回了YES而没有添加方法,该方法被调用
  20. // 在这个方法中,我们可以指定一个可以返回一个可以响应该方法的对象, 注意如果返回self就会死循环,这里返回的对象就是要转移寻找的列表,换成到Car类里面寻找run方法的实现
  21. - (id)forwardingTargetForSelector:(SEL)aSelector {
  22. // Car *car = [[Car alloc]init];
  23. // return car;
  24. return nil;
  25. }
  26. // 第三步, 如果forwardingTargetForSelector:返回了nil,则该方法会被调用,系统会询问我们要一个合法的『类型编码(Type Encoding)』也就是方法签名
  27. // 若返回 nil,则不会进入下一步,而是无法处理消息
  28. - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
  29. return [NSMethodSignature signatureWithObjCTypes:"v@:"];
  30. // return nil;
  31. }
  32. // 当实现了此方法后,-doesNotRecognizeSelector: 将不会被调用
  33. // 在这里进行消息转发
  34. - (void)forwardInvocation:(NSInvocation *)anInvocation {
  35. // 在这里可以改变方法选择器
  36. [anInvocation setSelector:@selector(unknown)];
  37. // 改变方法选择器后,需要指定消息的接收者
  38. [anInvocation invokeWithTarget:self];
  39. }
  40. - (void)unknown {
  41. NSLog(@"unkown method.......");
  42. }
  43. // 如果没有实现消息转发 forwardInvocation 则调用此方法
  44. - (void)doesNotRecognizeSelector:(SEL)aSelector {
  45. // NSLog(@"unresolved method :%@", NSStringFromSelector(aSelector));
  46. }
  47. @end
复制代码


回复

使用道具 举报