系统方法

NSLog(@"%s", __func__);  //打印出类的方法名称,如:

//打印结果:2018-02-22 10:52:15.394575+0800 DemoRuntime[1078:25503] -[ViewController printIvarList]

创建Class

 1 - (Class) createNewClass {
const char * className;
className = [@"Student" UTF8String];
Class kclass = objc_getClass(className);
//判断此类是否已经存在,如果存在则返回,不存在就创建
if (!kclass)
{
Class superClass = [NSObject class];
kclass = objc_allocateClassPair(superClass, className, );
}
return kclass;
}

注册类

  Class newClass = [self createNewClass];
id instanceObjects = [[newClass alloc] init];
NSLog(@"注册后的类实例化对象:%@", instanceObjects);

打印结果:


添加成员变量

 //添加成员变量
- (void) addNewVariable:(Class) newClass {
class_addIvar(newClass, [@"_stuName" UTF8String], sizeof(NSString *), log2(sizeof(id)), "@");
 }
 //动态添加变量
//入参:类Class,变量名char数组,变量类型大小size_t,变量在内存中的对齐方式,变量的type类型
//返回:添加结果,是否成功。
//* 1.只能给动态创建的类添加变量也就是用 objc_allocateClassPair 创建的类
//* 2.添加变量只能在函数 objc_allocateClassPair 和 class_getInstanceVariable 之间添加才有效
BOOL class_addIvar(Class cls, const char *name, size_t size, uint8_t alignment, const char *types)

注意:这个方法的调用要在objc_allocateClassPair方法之后和注册类objc_registerClassPair方法之前调用,否则没法动态添加成员变量。

这是因为方法和属性并不“属于”类实例,而成员变量“属于”类实例。我们所说的“类实例”概念,指的是一块内存区域,包含了isa指针和所有的成员变量。所以假如允许动态修改类成员变量布局,已经创建出的类实例就不符合类定义了,变成了无效对象。但方法定义是在objc_class中管理的,不管如何增删类方法,都不影响类实例的内存布局,已经创建出的类实例仍然可正常使用。

获取Class的成员变量名

 //    获取类的成员变量名
- (NSArray *)getVariableNamesByObject:(id)object
{
unsigned int numIvars = ;
// 获取类的所有成员变量
Ivar * ivars = class_copyIvarList([object class], &numIvars);
// 定义一个数组来接收获取的属性名
NSMutableArray *nameArray = [[NSMutableArray alloc] initWithCapacity:numIvars];
for(int i = ; i < numIvars; i++) {
// 得到单个的成员变量
Ivar thisIvar = ivars[i];
// 得到这个成员变量的类型
const char *type = ivar_getTypeEncoding(thisIvar);
NSString *stringType = [NSString stringWithCString:type encoding:NSUTF8StringEncoding];
// 此处判断非object-c类型时跳过
if (![stringType hasPrefix:@"@"]) {
continue;
}
// 得到成员变量名
NSString *variableName = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
[nameArray addObject:variableName]; // 这个函数可以得到成员变量的值
// object_getIvar(object, thisIvar) }
free(ivars);
return nameArray;
}

调用以后,结果为:


创建方法

第一个参数为类名,第二个参数为方法名,第三个参数是函数名,第四个参数是函数的返回值和参数的类型,v表是void,@表示id,:表示SEL。更多多定义参考:SELECTOR

    class_addMethod([kclass class], @selector(say:), (IMP)say, "v@:");
 //动态添加方法
//入参:类Class,方法名SEL,方法实现IMP,方法返回值各个参数类型等配置字符串
//返回:添加结果,是否成功。
//* 1.添加属性不用再objc_registerClassPair之前,因为添加属性其实就是添加变量的set 和 get方法而已
//* 2.添加的属性和变量不能用kvc设置值和取值
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

需要实现,这个方法


添加属性

 //添加一个属性
- (void) addProperties:(Class) newClass {
NSString *propertyName = @"stuSex";
objc_property_attribute_t type = { "T", "@\"NSString\"" };
objc_property_attribute_t ownership = { "C", "copy" };
objc_property_attribute_t backingivar = { "V", [propertyName UTF8String]};
objc_property_attribute_t attrs[] = { type, ownership, backingivar };
BOOL isOk=class_addProperty(newClass, [propertyName UTF8String], attrs, );
}
 //动态添加属性
//入参:类Class,属性名char数组,属性的配置属性,objc_property_attribute_t,属性的属性数量。
//返回:添加结果,是否成功。
BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount)

或者:

 + (void)addPropertyWithtarget:(id)target withPropertyName:(NSString *)propertyName withValue:(id)value {

     //先判断有没有这个属性,没有就添加,有就直接赋值
Ivar ivar = class_getInstanceVariable([target class], [[NSString stringWithFormat:@"_%@", propertyName] UTF8String]);
if (!ivar) {
return;
}
//objc_property_attribute_t所代表的意思可以调用getPropertyNameList打印,大概就能猜出
objc_property_attribute_t type = { "T", [[NSString stringWithFormat:@"@\"%@\"",NSStringFromClass([value class])] UTF8String] };
objc_property_attribute_t ownership = { "&", "N" };
objc_property_attribute_t backingivar = { "V", [[NSString stringWithFormat:@"_%@", propertyName] UTF8String] };
objc_property_attribute_t attrs[] = { type, ownership, backingivar };
if (class_addProperty([target class], [propertyName UTF8String], attrs, )) { //添加get和set方法
SEL getter = NSSelectorFromString(propertyName);
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]); BOOL suc0 = class_addMethod([target class], getter, (IMP)attribute0Getter, "@@:");
BOOL suc1 = class_addMethod([target class], setter, (IMP)attribute0Setter, "v@:@");
NSLog(@">>>>>>>>添加get和set成功OrFail:%@:%@",@(suc0),@(suc1)); NSLog(@">>>>>>>>1:%@",[target performSelector:getter withObject:nil]);
[target performSelector:setter withObject:@"为动态创建类先添加变量再添加属性"];
NSLog(@">>>>>>>>2:%@",[target performSelector:getter withObject:nil]); //赋值
[target setValue:value forKey:propertyName];
NSLog(@"%@", [target valueForKey:propertyName]); NSLog(@"创建属性Property成功");
}
}
 //get方法
NSString *attribute0Getter(id classInstance, SEL _cmd) {
Ivar ivar = class_getInstanceVariable([classInstance class], "_attribute0");//获取变量,如果没获取到说明不存在
return object_getIvar(classInstance, ivar);
} //set方法
void attribute0Setter(id classInstance, SEL _cmd, NSString *newName) {
Ivar ivar = class_getInstanceVariable([classInstance class], "_attribute0");//获取变量,如果没获取到说明不存在
id oldName = object_getIvar(classInstance, ivar);
if (oldName != newName) object_setIvar(classInstance, ivar, [newName copy]);
}
get方法:第一个个@代表返回的类型为非基本数据类型,如果返回的数据是int那么第一个字符应该为i set方法:第一个个v代表返回的类型为void,如果返回的数据是int那么第一个字符应该为i,最后一个@代表函数的第一个试用参数类型为非基本数据类型 set和get方法的共同部分是@:分别代表方法的两个默认函数target和SEL。

打印结果:

查看属性

 //    获取类的所有属性名
- (NSArray*)getPropertieNamesByObject:(id)object
{ unsigned int outCount, i; // 获取注册类的属性列表,第一个参数是类,第二个参数是接收类属性数目的变量
objc_property_t *properties = class_copyPropertyList([object class], &outCount);
// 定义一个数组来接收获取的属性名
NSMutableArray *nameArray = [[NSMutableArray alloc] initWithCapacity:outCount];
for (i = ; i < outCount; i++) {
// 通过循环来获取单个属性
objc_property_t property = properties[i];
// 取得属性名
NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
// 将得到的属性名放入数组中
[nameArray addObject:propertyName]; }
free(properties);
return nameArray;
}

打印结果:


查看方法

 -(void)getMethodsListByObject:(id) object {
unsigned int copycopyMethodListCount = ;
Method *methods = class_copyMethodList([object class], &copycopyMethodListCount);
for (NSInteger i = ; i < copycopyMethodListCount; i++) {
Method method = methods[i];
SEL name = method_getName(method);
NSLog(@">>>>>>>>2:copyMethodList:%@",NSStringFromSelector(name));
}
free(methods);//释放
NSLog(@"\n"); }

打印:


添加协议

 //添加协议
- (void)addProtocoalWithClass:(Class)class_1 {
BOOL result0 = class_addProtocol(class_1, NSProtocolFromString(@"UITableViewDelegate"));
NSLog(@">>>>>>>>3:添加协议成功"); /**
* 1.class_addProtocol 参数含义:第一个:要添加协议的类,第二个:协议对象
* 2.获取协议列表具体细节参照Class1里的内容
*/
unsigned int copyProtocolListCount = ;
Protocol * __unsafe_unretained *protocals = class_copyProtocolList(class_1, &copyProtocolListCount);
for (NSInteger i = ; i < copyProtocolListCount; i++) {
Protocol * protocal = protocals[i];
const char *name = protocol_getName(protocal);
NSLog(@">>>>>>>>4:copyProtocolList:%s",name);
}
free(protocals);//释放
NSLog(@"\n");
}

打印结果:

OC 反射-->动态创建类的更多相关文章

  1. C#——反射动态创建类的实例

    “反射”其实就是利用程序集的元数据信息. 反射可以有很多方法,编写程序时请先导入 System.Reflection 命名空间. 若要反射当前项目中的类(即当前项目已经引用它了),可以使用下面的写法. ...

  2. C#反射动态创建实例并调用方法

    在.Net 中,程序集(Assembly)中保存了元数据(MetaData)信息,因此就可以通过分析元数据来获取程序集中的内容,比如类,方法,属性等,这大大方便了在运行时去动态创建实例. MSDN解释 ...

  3. ios动态创建类Class

    [Objective-C Runtime动态加载]---动态创建类Class 动态创建类Class,动态添加Class成员变量与成员函数,动态变量赋值与取值,动态函数调用等方法 a.使用objc_al ...

  4. python动态创建类的声明

    动态创建类的声明 使用内置函数type,原型:class type(name, bases, dict)name是类的名字,相当于__class__bases是类的基类,元组,可以有多个基类,但是基类 ...

  5. StructureMap.dll 中的 GetInstance 重载 + 如何利用 反射动态创建泛型类

    public static T GetInstance<T>(ExplicitArguments args); // // Summary: // Creates a new instan ...

  6. C# 利用反射动态调用类成员

    用反射动态调用类成员,需要Type类的一个方法:InvokeMember.对该方法的声明如下(摘抄于MSDN): publicobject InvokeMember(    string name, ...

  7. 使用python type动态创建类

    使用python type动态创建类 X = type('X', (object,), dict(a=1))  # 产生一个新的类型 X 和下列方法class X(object):    a = 1效 ...

  8. Python中type()详解:动态创建类

    众所周知: type()函数可以查看变量的类型: 先看一个简单的列子来看一下type查看变量类型 class Animal(): pass a=Animal() print(type(a)) prin ...

  9. python-获取类名和方法名,动态创建类和方法及属性

    获取类名和方法名1.在函数外部获取函数名称,用.__name__获取2.在函数内部获取当前函数名称,用sys._getframe().f_code.co_name方法获取3.使用inspect模块动态 ...

随机推荐

  1. 动态补丁构建工具nuwa中的“坑”

    1. 继承android中的Application的类A1Application:并且A2Application继承自A1Application,并且配置在清单文件中name=".A2App ...

  2. idea找不到import project

    一.首先File->close project 关完后,在界面你就可以看到import project

  3. NumPy 广播机制(Broadcasting)

    一.何为广播机制 a.广播机制是Numpy(开源数值计算工具,用于处理大型矩阵)里一种向量化数组操作方法. b.Numpy的通用函数(Universal functions) 中要求输入的两个数组sh ...

  4. python摸爬滚打之day03----基本数据类型(int,str,bool)

    1.数据类型转换 字符串 ----> bool print( bool("hello") )  -----> True 数字----> bool print( b ...

  5. 洛谷P3245 大数 [HNOI2016] 莫队

    正解:莫队 解题报告: 传送门 这题首先要发现一个结论,是这样儿的: 若p不是10的约数(即2和5) 时,当第i位到第n位组成的数%p==第j位到第n位组成的数%p,那么第i位到第j位上的数组成的数% ...

  6. wordpress去掉category怎么操作让url更简洁友好

    用wordpress建站是比较流行的,全球将近25%的站点是用wordpress搭建的.有很多的模板.插件可以选择,当然最好还是能自己优化.URL固定链接就是之中一个基础的技巧.有网友问如何去掉url ...

  7. secure CRT常用的查看服务器日志命令

    tail -f  /(日志文件目录)   查看日志命令ctrl+c停止打印ls  -al  查看文件的详细信息路径等vi  /(日志文件目录)  打开日志/搜索字符退出:按ESC后,按“:”,输入q, ...

  8. eclipse 假死

    由于电脑关机,导致Eclipse非正常关闭,之后启动Eclipse发现一直启动不起来,于是从网上找了一些方法如下: 1.删除文件.snap 到<workspace>\.metadata\. ...

  9. 接口,定义接口的关键字是 interface 实现接口关键字是 implements

    当抽象类中的方法都是抽象的时候,这时可以将该抽象类用另一种形式定义和表示,就是接口interface特点:对于接口中常见的成员:而且这些成员都有固定的修饰符,不写就默认存在1:全局常量 :  都是 p ...

  10. linux中 /dev/null命令

    /dev/null :代表空设备文件 >  :代表重定向到哪里,例如:echo "123" > /home/123.txt1  :表示stdout标准输出,系统默认值是 ...