01.基本操作

1. 反射 NSString,Class,SEL,Protocol

FOUNDATION_EXPORT NSString *NSStringFromSelector(SEL aSelector);
FOUNDATION_EXPORT SEL NSSelectorFromString(NSString *aSelectorName);

FOUNDATION_EXPORT NSString *NSStringFromClass(Class aClass);
FOUNDATION_EXPORT Class _Nullable NSClassFromString(NSString *aClassName);

FOUNDATION_EXPORT NSString *NSStringFromProtocol(Protocol *proto) API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
FOUNDATION_EXPORT Protocol * _Nullable NSProtocolFromString(NSString *namestr) API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

2. 动态创建一个类

  • 创建一个继承NSObject的类,设定类名并初始化;

  • 为这个类增加一个实例变量,通过KVC给这个实例变量赋值。

  • 为这个类增加一个方法,在这个方法中打印一些值。

  • 通过这个类的实例调用新增的方法。

3. 获取一个类的所有方法

class_copyMethodList

实例方法

#import <objc/runtime.h>
@implementation NSObject (Runtime)

+ (NSArray *)fetchInstanceMethodList
{
    unsigned int count = 0;
    Method *methodList = class_copyMethodList(self, &count);

    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++)
    {
        Method method = methodList[i];
        SEL methodName = method_getName(method);
        [mutableList addObject:NSStringFromSelector(methodName)];
    }
    free(methodList);
    return [NSArray arrayWithArray:mutableList];
}

类方法

+ (NSArray *)fetchClassMethodList
{
    unsigned int count = 0;
    Method *methodList = class_copyMethodList(object_getClass(self), &count);

    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++)
    {
        Method method = methodList[i];
        SEL methodName = method_getName(method);
        [mutableList addObject:NSStringFromSelector(methodName)];
    }
    free(methodList);
    return [NSArray arrayWithArray:mutableList];
}

4. 获取一个类的所有成员变量

class_copyIvarList

- (void) getAllVariable {
    unsigned int count = 0;
    //获取类的一个包含所有变量的列表,IVar是runtime声明的一个宏,是实例变量的意思.
    Ivar *allVariables = class_copyIvarList([self class], &count);
    for(int i = 0;i<count;i++)
    {
        //遍历每一个变量,包括名称和类型(此处没有星号"*")
        Ivar ivar = allVariables[i];
        const char *Variablename = ivar_getName(ivar); //获取成员变量名称
        const char *VariableType = ivar_getTypeEncoding(ivar); //获取成员变量类型
        NSLog(@"(Name: %s) ----- (Type:%s)",Variablename,VariableType);
    }
    free(allVariables);
}

5. 获取一个类的所有属性变量

class_copyPropertyList

- (void) getAllPropertyList {
    unsigned int count = 0;
    objc_property_t *allVariables = class_copyPropertyList([self class], &count);
    for(int i = 0;i<count;i++)
    {
        //遍历每一个变量,包括名称和类型(此处没有星号"*")
        objc_property_t property = allVariables[i];
        const char *Variablename = property_getName(property); //获取属性变量名称
        const char *VariableType = property_getAttributes(property); //获取属性变量的属性
        NSLog(@"(Name: %s) ----- (Type:%s)",Variablename,VariableType);
    }
    free(allVariables);
}
  //还有一种写法,注意 object_getClass 中的参数需要是一个对象实例,
  // 就是说 object_getClass([ChangePayPasswordViewController new]),
  //和 ChangePayPasswordViewController.Class 意义是一样的
  unsigned int a;
  objc_property_t * result = class_copyPropertyList(object_getClass([ChangePayPasswordViewController new]), &a);

6. 获取协议列表

 + (NSArray *)fetchProtocolList
{
    unsigned int count = 0;
    __unsafe_unretained Protocol **protocolList = class_copyProtocolList(self, &count);

    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++ )
    {
        Protocol *protocol = protocolList[i];
        const char *protocolName = protocol_getName(protocol);
        [mutableList addObject:[NSString stringWithUTF8String:protocolName]];
    }
    return [NSArray arrayWithArray:mutableList];
}

7. 动态给一个类新增一个方法

/* 动态添加方法:
 第一个参数表示Class cls 类型;
 第二个参数表示待调用的方法名称;
 第三个参数(IMP)myAddingFunction,IMP一个函数指针,这里表示指定具体实现方法myAddingFunction;
 第四个参数表方法的参数,0代表没有参数;
 */
class_addMethod([person class], @selector(myAddingFunction), (IMP)myAddingFunction, 0);
//调用方法 【如果使用[per NewMethod]调用方法,在ARC下会报“no visible @interface"错误】
[person performSelector:@selector(myAddingFunction)];

//具体的实现(方法的内部都默认包含两个参数Class类和SEL方法,被称为隐式参数。)
int myAddingFunction(id self, SEL _cmd){
    NSLog(@"已新增方法:NewMethod");
    return 1;
}

8. 动态增加实例变量

BOOL isSuccess = class_addIvar(MyClass, "test", sizeof(NSString *), 0, "@");
// 三目运算符
isSuccess?NSLog(@"添加变量成功"):NSLog(@"添加变量失败");

参数一、类名
参数二、属性名称
参数三、开辟字节长度
参数四、对其方式
参数五、参数类型 “@” 官方解释 An object (whether statically typed or typed id) (对象 静态类型或者id类型)

9. 动态改变对象的某个变量值

  • 可以是属性变量(注意加 _ ),也可以是私有的全局变量

Person *person = [[Person alloc]init];
person.name = @"asdas";
NSLog(@"%@",person.name);
[self editObjectIvar:person :@"_name" :@"新属性"];
NSLog(@"new :%@",person.name);

- (void)editObjectIvar :(id)object
                       :(NSString *)IvarStr
                       :(NSString *)IvarNewStr

{
    unsigned int count = 0;
    Ivar *allList = class_copyIvarList([object class], &count);
    for(int i = 0;i<count;i++)
    {
        //遍历每一个变量,包括名称和类型(此处没有星号"*")
        Ivar ivar = allList[i];
        const char *Variablename = ivar_getName(ivar); //获取成员变量名称
        if ([[NSString stringWithUTF8String:Variablename] isEqualToString:IvarStr]) {
            object_setIvar(object, ivar, IvarNewStr); //name属性Tom被强制改为Mike。
        }
    }
    free(allList);
}

10. 属性关联

11. 交换方法

参考

https://www.jianshu.com/p/8225526096c7

Last updated