一、Runtime 概念部分 之 Ivar

本文github地址 https://github.com/ICZhuang/Runtime 朋友们如果喜欢收藏即可,不建议转载,笔者会不定期update文章,github 也会同步更新,喜欢就star一下吧。

笔者取名概念部分,是因为笔者认为理解 Runtime 的基础就是先熟悉各组织,这些组织包括 Ivar、Property、Method、Category、Protocol、Class、Object 和 Message

Ivar


指类中的一个成员变量,如类RTModel中的 _ivar01、_ivar02、_ivar03,包括 _property01 / _property02

@interface RTModel : NSObject {
    @public NSString *_ivar_01;
}
@property (nonatomic,  assign,  readonly)   NSInteger    i_property_01;
@property (nonatomic,  strong)              NSArray     *a_property_02;
@end

@interface RTModel () {
    NSString    *_ivar_02;
}
@end
 
@implementation RTModel {
    NSInteger   *_ivar_03;
}
@end

通过 class_copyIvarList 函数可以将成员获得类的 Ivar 列表,但是父类的Ivar 没有包含在里面,注意使用完成后需要通过 free() 将结果释放掉。

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

访问Ivar


获得了Ivar列表即可遍历每个Ivar,通过以下方法取得Ivar的特定信息
1、取name

const char *ivar_getName(Ivar v); 

2、取 Type Encoding

const char *ivar_getTypeEncoding(Ivar v);

3、取 offset 偏移量

ptrdiff_t ivar_getOffset(Ivar v); 

类型编码(Type Encodings)


编译器可将 <u>类型</u> 编码成一个字符串,这个字符串就是类型编码(Type Encodings)用于描述变量类型。通过@encode()即可获得某个类型的编码,任何能在sizeof()使用的参数都可以传递给@encode()。详细请参考 ‘Objective-C Runtime Programming Guide > Type Encodings’

比如RTModel中各Ivar的type encoding, _ivar_03 的类型是NSInteger指针, encoding表示成^q

image-01
image-01

关于类型编码也是一个基础概念,Runtime 中很多地方依靠这个概念实现的。有必要先了解一下。
英文文档 Objective-C Runtime Programming Guide > Type Encoding
笔者译文 Type Encoding & Declared Property

偏移量


每个Ivar在类中是顺序排列的,它们有自己的位置,偏移量就是用来记录它的位置的。比如RTModel中的Ivar的偏移量就如图所示,对象在内存中通过指针引用者,假设这个指针指向的地址为A,那么 _ivar_01 距离A的距离就是8个字节,_ivar_02 距离A为16字节。

image_02
image_02

但是在类的category中声明的则不是Ivar,它只是声明,并不分配空间,所以并不是Ivar。

遍历


遍历类中所有的Ivar,并获取它们的信息。

- (void)getIvars {
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList(RTModel.class, &count);
    
    Ivar ivar;
    for (int index = 0; index < count; ++index) {
        ivar = ivars[index];
        
        printf("%s - %s\n", ivar_getName(ivar), ivar_getTypeEncoding(ivar));
    }
}

扩展认识

Ivar 其实是结构体objc_ivar,这么说不准确,准确来说它是一个objc_ivar结构体的指针,objc_ivar就代表着一个成员变量,以上所列关于取得Ivar信息的方法都是Runtime内部在操作这个结构体,取得的信息也是 objc_ivar结构体中的某个字段的值。以上方法取得的值分别对应ivar_name/ivar_type/ivar_offset字段的值。

(space 猜想是Ivar内存对齐的后的剩余字节,没去证实,暂且不说)

struct objc_ivar {
    char *ivar_name                                          OBJC2_UNAVAILABLE;
    char *ivar_type                                          OBJC2_UNAVAILABLE;
    int ivar_offset                                          OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
} 

事实上,Runtime 的大部分方法都是在操作某一个结构体,找到对应的结构体,就可以看出该结构体具备什么字段,进而知道方法是干什么用的了。比如以下结构体

typedef struct objc_method *Method;
typedef struct objc_ivar *Ivar;
typedef struct objc_category *Category;
typedef struct objc_property *objc_property_t;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 我们常常会听说 Objective-C 是一门动态语言,那么这个「动态」表现在哪呢?我想最主要的表现就是 Obje...
    Ethan_Struggle阅读 6,577评论 0 7
  • 这篇文章完全是基于南峰子老师博客的转载 这篇文章完全是基于南峰子老师博客的转载 这篇文章完全是基于南峰子老师博客的...
    西木阅读 30,712评论 33 466
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 5,826评论 0 9
  • 对于从事 iOS 开发人员来说,所有的人都会答出【runtime 是运行时】什么情况下用runtime?大部分人能...
    梦夜繁星阅读 9,082评论 7 64
  • 前言 我第一次开始重视Objective-C Runtime是从2014年11月1日,@唐巧老师在微博上发的一条微...
    一缕殇流化隐半边冰霜阅读 47,242评论 178 616