IOS Runtime的用法
什么是runtime?
1> runtime是一套底层的C语言API(包含很多强大实用的C语言数据类型、C语言函数)
2> 实际上,平时我们编写的OC代码,底层都是基于runtime实现的
* 也就是说,平时我们编写的OC代码,最终都是转成了底层的runtime代码(C语言代码)
runtime有啥用?
1> 能动态产生一个类、一个成员变量、一个方法
2> 能动态修改一个类、一个成员变量、一个方法
3> 能动态删除一个类、一个成员变量、一个方法
常见的函数、头文件
#import <objc/runtime.h> : 成员变量、类、方法
Ivar * class_copyIvarList : 获得某个类内部的所有成员变量
Method * class_copyMethodList : 获得某个类内部的所有方法
Method class_getInstanceMethod : 获得某个实例方法(对象方法,减号-开头)
Method class_getClassMethod : 获得某个类方法(加号+开头)
method_exchangeImplementations : 交换2个方法的具体实现
#import <objc/message.h> : 消息机制
objc_msgSend(....)
#import "HMViewController.h" #import "HMPerson.h" #import <objc/runtime.h> #import <objc/message.h> @interface HMViewController () @property (weak, nonatomic) IBOutlet UIImageView *iconView1; @property (weak, nonatomic) IBOutlet UIImageView *iconView2; @property (nonatomic, strong) NSMutableArray *names; @property (nonatomic, strong) NSArray *books; @end @implementation HMViewController - (NSMutableArray *)names { if (_names == nil) { self.names = [NSMutableArray array]; } return _names; } - (void)viewDidLoad { [super viewDidLoad]; // NSDictionary *info = @{@"name" : @"jack", @"age" : @10}; // // NSString *key = nil; // // NSLog(@"%@", info[key]); NSMutableDictionary *info = [NSMutableDictionary dictionary]; info[@"name"] = nil; // self.books = @[@"kiuhua", @"xxx"]; // // NSLog(@"%@", self.books[4]); // [self addName:@"jack"]; // [self addName:@"rose"]; // [self addName:@"jim"]; // // NSLog(@"%@", self.names[4]); // NSLog(@"%@", [self.names objectAtIndex:4]); } - (void)addName:(NSString *)name { [self.names addObject:name]; } - (void)imageSwizzle { // 什么是iOS Swizzle?利用运行时函数交换2个方法的实现 // BOOL iOS7 = [[UIDevice currentDevice].systemVersion floatValue] >= 7.0; // if (iOS7) { // self.iconView1.image = [UIImage imageNamed:@"face_os7"]; // self.iconView2.image = [UIImage imageNamed:@"vip_os7"]; // } else { // self.iconView1.image = [UIImage imageNamed:@"face"]; // self.iconView2.image = [UIImage imageNamed:@"vip"]; // } self.iconView1.image = [UIImage imageNamed:@"face"]; self.iconView2.image = [UIImage imageNamed:@"vip"]; } - (void)testRuntimeIvar { // Ivar : 成员变量 unsigned int count = 0; // 获得所有的成员变量 Ivar *ivars = class_copyIvarList([HMPerson class], &count); for (int i = 0; i<count; i++) { // 取得i位置的成员变量 Ivar ivar = ivars[i]; const char *name = ivar_getName(ivar); const char *type = ivar_getTypeEncoding(ivar); NSLog(@"%d %s %s", i, name, type); } // HMPerson *p = [[HMPerson alloc] init]; // objc_msgSend(p, @selector(setAge:), 20); // NSLog(@"%d", p.age); }
HMPerson.h /.m(获取所有成员变量)
#import <Foundation/Foundation.h> @interface HMPerson : NSObject <NSCoding> @property (nonatomic, assign) int age; @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) double height; - (void)run; @end
#import "HMPerson.h" #import <objc/runtime.h> @implementation HMPerson - (void)run { NSLog(@"run----"); } - (void)encodeWithCoder:(NSCoder *)encoder { unsigned int count = 0; Ivar *ivars = class_copyIvarList([HMPerson class], &count); for (int i = 0; i<count; i++) { // 取得i位置的成员变量 Ivar ivar = ivars[i]; const char *name = ivar_getName(ivar); NSString *key = [NSString stringWithUTF8String:name]; [encoder encodeObject:[self valueForKeyPath:key] forKey:key]; } } @end
UIImage+Extension(交换2个方法的实现)
#import <objc/runtime.h> @implementation UIImage (Extension) /** * 只要分类被装载到内存中,就会调用1次 */ + (void)load { Method otherMehtod = class_getClassMethod(self, @selector(imageWithName:)); Method originMehtod = class_getClassMethod(self, @selector(imageNamed:)); // 交换2个方法的实现 method_exchangeImplementations(otherMehtod, originMehtod); } + (UIImage *)imageWithName:(NSString *)name { BOOL iOS7 = [[UIDevice currentDevice].systemVersion floatValue] >= 7.0; UIImage *image = nil; if (iOS7) { NSString *newName = [name stringByAppendingString:@"_os7"]; image = [UIImage imageWithName:newName]; } if (image == nil) { image = [UIImage imageWithName:name]; } return image; } @end
NSObject+Extension(交换2个方法的实现)
#import <objc/runtime.h> @implementation NSObject(Extension) + (void)swizzleClassMethod:(Class)class originSelector:(SEL)originSelector otherSelector:(SEL)otherSelector { Method otherMehtod = class_getClassMethod(class, otherSelector); Method originMehtod = class_getClassMethod(class, originSelector); // 交换2个方法的实现 method_exchangeImplementations(otherMehtod, originMehtod); } + (void)swizzleInstanceMethod:(Class)class originSelector:(SEL)originSelector otherSelector:(SEL)otherSelector { Method otherMehtod = class_getInstanceMethod(class, otherSelector); Method originMehtod = class_getInstanceMethod(class, originSelector); // 交换2个方法的实现 method_exchangeImplementations(otherMehtod, originMehtod); } @end @implementation NSArray(Extension) + (void)load { [self swizzleInstanceMethod:NSClassFromString(@"__NSArrayI") originSelector:@selector(objectAtIndex:) otherSelector:@selector(hm_objectAtIndex:)]; } - (id)hm_objectAtIndex:(NSUInteger)index { if (index < self.count) { return [self hm_objectAtIndex:index]; } else { return nil; } } @end @implementation NSMutableArray(Extension) + (void)load { [self swizzleInstanceMethod:NSClassFromString(@"__NSArrayM") originSelector:@selector(addObject:) otherSelector:@selector(hm_addObject:)]; [self swizzleInstanceMethod:NSClassFromString(@"__NSArrayM") originSelector:@selector(objectAtIndex:) otherSelector:@selector(hm_objectAtIndex:)]; } - (void)hm_addObject:(id)object { if (object != nil) { [self hm_addObject:object]; } } - (id)hm_objectAtIndex:(NSUInteger)index { if (index < self.count) { return [self hm_objectAtIndex:index]; } else { return nil; } } @end