runtime的使用先導(dǎo)入runtime類(lèi)
#import <objc/runtime.h>
runtime 可以對(duì)類(lèi)操作
舉個(gè)例子
先創(chuàng)建一個(gè)Person類(lèi)
在.h中聲明方法
/*
1 + resolveInstanceMethod:(SEL)sel // 為一個(gè)實(shí)例方法動(dòng)態(tài)添加實(shí)現(xiàn)
+ resolveClassMethod:(SEL)sel // 為一個(gè)類(lèi)方法動(dòng)態(tài)添加實(shí)現(xiàn)
2 - (id)forwardingTargetForSelector:(SEL)aSelector
//為沒(méi)有實(shí)現(xiàn)的方法指定一個(gè)對(duì)象
3 - (void)forwardInvocation:(NSInvocation *)anInvocation
//子類(lèi)重載這個(gè)方法為消息指定其他對(duì)象
*/
在.m中使用
#import "Person.h"
#import <objc/runtime.h>
@implementation Person
/*
Ivar *class_copyIvarList(Class cls, unsigned int *outCount) //獲取所有成員變量
const char *ivar_getName(Ivar v) //獲取某個(gè)成員變量的名字
const char *ivar_getTypeEncoding(Ivar v) //獲取某個(gè)成員變量的類(lèi)型編碼
Ivar class_getInstanceVariable(Class cls, const char *name) //獲取某個(gè)類(lèi)中指定名稱(chēng)的成員變量
id object_getIvar(id obj, Ivar ivar) //獲取某個(gè)對(duì)象中的某個(gè)成員變量的值
void object_setIvar(id obj, Ivar ivar, id value) //設(shè)置某個(gè)對(duì)象的某個(gè)成員變量的值
TypeEncoding:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW1
*/
- (NSString *)description
{
// class:要獲取的某個(gè)類(lèi)掂林,outCount:通過(guò)這一個(gè)函數(shù)執(zhí)行之后會(huì)將成員變量的個(gè)數(shù)復(fù)制到此
unsigned int outCount;
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i++) {
// 每次獲取一個(gè)成員變量
Ivar ivar = ivarList[i];
// 打印成員變量的類(lèi)型編碼
NSLog(@"name = %s", ivar_getName(ivar));
NSLog(@"type = %s", ivar_getTypeEncoding(ivar));
}
return nil;
}
+ (Person *)personWithName:(NSString *)name gender:(NSString *)gender age:(NSNumber *)age weight:(NSInteger)weight
{
Person *person = [Person new];
unsigned int outCount;
Ivar *ivarList = class_copyIvarList(self, &outCount);
// obj:要設(shè)置的對(duì)象 ivar:要設(shè)置的對(duì)象的某一個(gè)屬性value:value
object_setIvar(person, ivarList[0], name);
object_setIvar(person, ivarList[1], gender);
object_setIvar(person, ivarList[2], age);
object_setIvar(person, ivarList[3], @(weight));
return person;
}
- (void)getPersonMessage
{
unsigned int outCount;
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i++) {
NSLog(@"name = %s, value = %@", ivar_getName(ivarList[i]), object_getIvar(self, ivarList[i]));
}
}
// 編碼
- (void)encodeWithCoder:(NSCoder *)aCoder
{
unsigned int outCount;
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i++) {
const char *cName = ivar_getName(ivarList[i]);
NSString *name = [NSString stringWithUTF8String:cName];
[aCoder encodeObject:[self valueForKey:name] forKey:name];
}
}
// 解碼
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
unsigned int outCount;
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i++) {
const char *cName = ivar_getName(ivarList[i]);
NSString *name = [NSString stringWithUTF8String:cName];
[self setValue:[aDecoder decodeObjectForKey:name] forKey:name];
}
}
return self;
}
/*
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
NSString *selString = NSStringFromSelector(sel);
if ([selString isEqualToString:@"walkOnTheStreet:"]) {
// 為一個(gè)沒(méi)有實(shí)現(xiàn)的方法動(dòng)態(tài)添加實(shí)現(xiàn)
cls:類(lèi)
name:沒(méi)有實(shí)現(xiàn)的方法名
IMP:要添加的實(shí)現(xiàn)
types:動(dòng)態(tài)添加的實(shí)現(xiàn)的類(lèi)型編碼
class_addMethod(self, @selector(walkOnTheStreet:), (IMP)walkFunc, "V@:@");
}
return [super resolveInstanceMethod:sel];
}
*/
void walkFunc(id self, SEL sel, NSString *str){
NSLog(@"Person -- %s, %@", __func__, str);
}
// 切換消息轉(zhuǎn)換對(duì)象 方式一
/*
- (id)forwardingTargetForSelector:(SEL)aSelector
{
NSString *selString = NSStringFromSelector(aSelector);
if ([selString isEqualToString:@"walkOnTheStreet:"]) {
self.dog = [Dog new];
return self.dog;
}
else {
return [super forwardingTargetForSelector:aSelector];
}
}
*/
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([Dog instancesRespondToSelector:anInvocation.selector]) {
self.dog = [Dog new];
[anInvocation invokeWithTarget:self.dog];
}
}
// 給方法制定一個(gè)有效的簽名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];
if (!methodSignature) {
methodSignature = [Dog instanceMethodSignatureForSelector:aSelector];
}
return methodSignature;
}
runtime在類(lèi)目中的使用
/*
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) //為某個(gè)類(lèi)關(guān)聯(lián)某個(gè)對(duì)象
id objc_getAssociatedObject(id object, const void *key)
//獲取到某個(gè)類(lèi)的某個(gè)關(guān)聯(lián)對(duì)象
void objc_removeAssociatedObjects(id object) //移除已經(jīng)關(guān)聯(lián)的對(duì)象
*/
可以為某個(gè)類(lèi)關(guān)聯(lián)對(duì)象
- (void)setName:(NSString *)name {
// objc:要關(guān)聯(lián)的對(duì)象 key:成員變量對(duì)應(yīng)的key值宪躯,@selector(屬性名)value:value
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name {
return objc_getAssociatedObject(self, @selector(name));
}