iOS runtime方法详解之类操作

本文详细介绍了iOS Runtime中的类操作方法,包括获取类名、超类、判断是否为元类、获取实例大小、获取及添加实例变量等,并通过实例展示了各个方法的使用和其返回信息的解析。
摘要由CSDN通过智能技术生成

Working with Classes

方法声明:

const char * class_getName ( Class cls );

描述:获取cls类对象的名称

举例:

NSLog(@"%s", class_getName([Book class]));

打印信息:

2015-09-14 10:52:35.147 AppTest[5839:81954] Book


方法声明:

Class class_getSuperclass ( Class cls );

描述:获取cls类对象的超类

举例:

NSLog(@"%@", class_getSuperclass([Book class]));

打印信息:

2015-09-14 10:55:23.402 AppTest[5958:84223] BaseModel


方法声明:

BOOL class_isMetaClass ( Class cls );

描述:判断cls类对象是否是元类对象

举例:

    NSObject *object = [[NSObject alloc] init];
    Class class = [NSObject class];
    
    BOOL yup = class_isMetaClass(object_getClass(class));
    BOOL nope = class_isMetaClass(object_getClass(object));
    NSLog(@"%d,%d", yup,nope);

打印信息:

2015-09-14 14:18:43.622 AppTest[9738:145947] 1,0


方法声明:

size_t class_getInstanceSize ( Class cls );

描述:获取cls类对象的实例大小(字节数),我理解是创建一个类的实例所需要的内存大小;

举例:

@interface BaseModel : NSObject
{
}
// Properties
@property(copy, nonatomic) NSString *className;
//
// Methods
- (NSString *)jsonValue;
- (NSDictionary *)dictionaryValue;
- (NSDictionary *)propertyDictionary;
- (BOOL)isEqualToModel:(BaseModel *)model;
@end
@interface Book : BaseModel
{
    @private
    NSString* _privateName;
}
@property (strong, nonatomic) NSString *author;
@property (assign, nonatomic) NSUInteger pages;
@property (strong, nonatomic) Pen *pen;

@interface Pen : BaseModel

@property (strong, nonatomic) NSString *color;
@property (assign, nonatomic) int type;

    Book *book = [[Book alloc]init];
    NSLog(@"%zu", class_getInstanceSize([NSObject class]));
    NSLog(@"%zu", class_getInstanceSize([BaseModel class]));
    NSLog(@"%zu", class_getInstanceSize([Book class]));
    NSLog(@"%zu", class_getInstanceSize([Pen class]));
    NSLog(@"sizeof myObject: %ld", sizeof(book));
打印信息:

2015-09-14 12:08:11.992 AppTest[8644:128563] 8

2015-09-14 12:08:11.993 AppTest[8644:128563] 16

2015-09-14 12:08:11.993 AppTest[8644:128563] 48

2015-09-14 12:08:11.993 AppTest[8644:128563] 32

2015-09-14 12:08:11.993 AppTest[8644:128563] sizeof myObject: 8

说明:

从最后一个打印信息可以看出64位下指针大小是8个字节,那么基类NSObject的大小正好是8个字节,因为它的成员变量就一个isa指针;因为方法是所有实例对象共享的,所以不会占用对象的存储空间,BaseModel除了isa新增了className属性,因此是2*8;这里的Book中pen是8,因为它只是一个指针变量;而Pen中type只占4个字节,之所以总共占有是32字节是因为字节对齐的原因;


方法声明:

Ivar class_getInstanceVariable ( Class cls, const char *name );

描述:获取cls类的名称为name的成员变量的详细信息,这个信息返回给Ivar类型的结构体

举例:

  Ivar ivar = class_getInstanceVariable([Book class], "_privateName");
  NSLog(@"%s,%s,%td", ivar_getName(ivar),ivar_getTypeEncoding(ivar),ivar_getOffset(ivar));
    
  ivar = class_getInstanceVariable([Book class], "_pen");
  NSLog(@"%s,%s,%td", ivar_getName(ivar),ivar_getTypeEncoding(ivar),ivar_getOffset(ivar));

打印信息:

2015-09-14 17:11:16.668 AppTest[16182:244363] _privateName,@"NSString",16

2015-09-14 17:11:16.669 AppTest[16182:244363] _pen,@"Pen",40


方法声明:

Ivar class_getClassVariable ( Class cls, const char *name );

描述:获取cls类的名称为name的类变量的详细信息,这个信息返回给Ivar类型的结构体

举例:

  Ivar ivar = class_getClassVariable([Book class], "isa");
  NSLog(@"%s,%s,%td", ivar_getName(ivar),ivar_getTypeEncoding(ivar),ivar_getOffset(ivar));

打印信息:

2015-09-14 17:09:27.278 AppTest[16092:242813] isa,#,0

说明:个人理解OC是没有类变量的,这里应该是指的元类对象,元类对象只有一个变量就是isa,可以参考http://stackoverflow.com/questions/1980703/what-does-class-getclassvariable-do理解class_getClassVariable(cls, name) merely calls class_getInstanceVariable(cls->isa, name)


方法声明:

BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char*types );

描述:给一个类添加新的实例变量,成功则返回YES;

这个方法只能在 objc_allocateClassPair 和 objc_registerClassPair之间调用,而不能给一个已经存在的类添加实例变量;

这个cls不能是元类,给一个元类添加实例变量是不被支持的;

实例变量的最小对齐方式为1。实例变量的最小对齐取决于变量的类型和机器的体系结构。对于任何一种类型的指针变量,通过log2(sizeof(pointer_type))方法得到。

举例:参考动态添加类

方法声明:

Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );

描述:获取类声明的实例变量,返回所有实例变量描述信息的数组的指针,数组的类型是Ivar这个数组中不包含父类的实例变量outCount指针返回数组的个数,最后使用完以后要通过free()释放这个数组指针;

举例:

    Class cls = [Book class];
    
    unsigned int ivarsCnt = 0;
    // 获取类成员变量列表,ivarsCnt为类成员数量
    Ivar *ivars = class_copyIvarList(cls, &ivarsCnt);
    
    // 遍历成员变量列表,其中每个变量都是Ivar类型的结构体
    for (const Ivar *p = ivars; p < ivars + ivarsCnt; p++)
    {
        Ivar const ivar = *p;
        NSLog(@"ivar: %@", [NSString stringWithUTF8String:ivar_getName(ivar)]);
    }
    free(ivars);

打印信息:

2015-09-15 17:25:03.192 AppTest[17305:227452] ivar: _privateName

2015-09-15 17:27:01.071 AppTest[17305:227452] ivar: _author

2015-09-15 17:27:01.071 AppTest[17305:227452] ivar: _pages

2015-09-15 17:27:01.071 AppTest[17305:227452] ivar: _pen


方法声明:

const uint8_t * class_getIvarLayout ( Class cls );

描述:返回给定类的实例变量布局(这个布局指的是否是强引用)的描述信息

举例:(见下面例子)


方法声明:

void class_setIvarLayout ( Class cls, const uint8_t *layout );

描述:设定给定类的实例变量的布局(这个布局指的是强引用

举例:(见下面例子)


方法声明:

const uint8_t * class_getWeakIvarLayout ( Class cls );

描述:返回给定类的实例变量布局(这个布局指的是否是弱引用)的描述信息

举例:(见下面例子)


方法声明:

void class_setWeakIvarLayout ( Class cls, const uint8_t *layout );

描述:设定给定类的实例变量的布局(这个布局指的是弱引用

举例:

@interface Book : BaseModel
{
@private
    __strong id ivar0;
    __weak id ivar1;
    __strong id ivar2;
    __weak id ivar3;
}

@property (strong, nonatomic) NSString *ivar4;
@property (weak, nonatomic) NSString *ivar5;

@end

    Class cls = [Book class];
    const uint8_t *ret = class_getIvarLayout(cls);
    const uint8_t *ret1 = class_getWeakIvarLayout(cls);

    int i=0;
    uint8_t value = ret[i];
    while (value != 0x0) {
        printf("\\x%02x",value);
        value = ret[++i];
    }
    printf("\r\n");
    i=0;
    value = ret1[i];
    while (value != 0x0) {
        printf("\\x%02x",value);
        value = ret1[++i];
    }

打印信息:

\x01\x11\x11\x10

\x11\x11\x11


说明:第一行是强引用的描述信息,x01表示0个非strong,1个strong;

                           x11表示1个非strong,1个strong;

                           x11表示1个非strong,1个strong;

                           x10表示1个非strong,0个strong;

     第二行是弱引用的描述信息,x11表示1个非weak,1个weak

                           x11表示1个非weak,1个weak

                           x11表示1个非weak,1个weak


这里我有个疑问,通过两个设置方法重新设置引用类型以后,再次获取布局信息还是原来的信息,也就是设置无效,求解!代码如下:


    Class cls = [Book class];
    unsigned char lay[1] ;
    lay[0] = 0x15;
    
    unsigned char lay1[2] ;
    lay1[0] = 0x01;
    lay1[1] = 0x50;
    
    class_setIvarLayout ( cls, lay );
    class_setWeakIvarLayout(cls, lay1 );
    
    const uint8_t *ret = class_getIvarLayout(cls);
    const uint8_t *ret1 = class_getWeakIvarLayout(cls);
    
    int i=0;
    uint8_t value = ret[i];
    while (value != 0x0) {
        printf("%02x",value);
        value = ret[++i];
    }
    printf("\r\n");
    i=0;
    value = ret1[i];
    while (value != 0x0) {
        printf("%02x",value);
        value = ret1[++i];
    }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值