美文网首页基础知识
iOS中成员变量的内存偏移量(ivar_offset)研究

iOS中成员变量的内存偏移量(ivar_offset)研究

作者: Shenry | 来源:发表于2017-11-05 18:10 被阅读204次

    在学习Runtime的过程中,自己对objc_ivar中ivar_offset的作用不太理解,所以自己建立了一个工程来研究理解。ivar_offset是指内存偏移量,即该成员变量对于该对象的内存地址偏移了多少,setter和getter方法均会根据此地址来改变该成员属性,那么如果是继承自一个父类,该成员变量的地址又会有什么变化呢?

    我们新建两个类,father和son,father继承自NSObject,son继承自father。

    1.先让son有一个数组属性,叫做girls:
    #import "Father.h"
    
    @interface Son : Father
    
    @property (nonatomic, strong) NSArray *girls;
    
    @end
    
    2.然后我们利用Runtime技术打印该变量的偏移量:
    #import "ViewController.h"
    #import <objc/message.h>
    #import "Son.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
         Ivar var_instance_girls = class_getInstanceVariable([Son class], "_girls");
        ptrdiff_t offset_var_girls = ivar_getOffset(var_instance_girls);
    
        NSLog(@"Grils Offset:%td", offset_var_girls);
    }
    

    控制台的结果如下:

    Grils Offset:8
    

    偏移结果为8,正对应64-bit系统下一个对象指针为8字节。

    3.然后我们给son添加另外一个数组属性叫做cars,然后打印cars的offset:

    son:

    #import "Father.h"
    
    @interface Son : Father
    
    @property (nonatomic, strong) NSArray *girls;
    @property (nonatomic, strong) NSArray *cars;
    
    @end
    

    viewcontroller:

    #import "ViewController.h"
    #import <objc/message.h>
    #import "Son.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        Ivar var_instance_girls = class_getInstanceVariable([Son class], "_girls");
        ptrdiff_t offset_var_girls = ivar_getOffset(var_instance_girls);
        NSLog(@"Grils Offset:%td", offset_var_girls);
    
        Ivar var_instance_cars = class_getInstanceVariable([Son class], "_cars");
        ptrdiff_t offset_var_cars = ivar_getOffset(var_instance_cars);
        NSLog(@"Cars Offset:%td", offset_var_cars);
    }
    
    @end
    

    此时,打印结果如下:

    Grils Offset:8
    Cars Offset:16
    

    这说明新增的成员变量又偏移了一个成员指针的大小,放在前一个成员变量的后面。那么假如father类新增一个成员变量,那么son的成员变量的offset会发生什么变化呢?

    4.我们给father增加一个成员变量叫做money:
    #import <Foundation/Foundation.h>
    
    @interface Father : NSObject
    
    @property (nonatomic, strong) NSArray *money;
    
    @end
    

    然后打印son的money属性的offset:

    #import "ViewController.h"
    #import <objc/message.h>
    #import "Son.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        Ivar var_instance_girls = class_getInstanceVariable([Son class], "_girls");
        ptrdiff_t offset_var_girls = ivar_getOffset(var_instance_girls);
        NSLog(@"Grils Offset:%td", offset_var_girls);
    
        Ivar var_instance_cars = class_getInstanceVariable([Son class], "_cars");
        ptrdiff_t offset_var_cars = ivar_getOffset(var_instance_cars);
        NSLog(@"Cars Offset:%td", offset_var_cars);
        
        Ivar var_instance_money = class_getInstanceVariable([Son class], "_money");
        ptrdiff_t offset_var_money = ivar_getOffset(var_instance_money);
        NSLog(@"Money Offset:%td", offset_var_money);
    }
    
    @end
    

    此时,打印结果如下:

    Grils Offset:16
    Cars Offset:24
    Money Offset:8
    

    我们发现,father新添的成员变量money被排在了第一个位置,而son中的成员变量grils和cars均被向后偏移了。而这正是继承关系应该有的情况。子类继承父类,当然是要优先将父类的成员变量放到前面,然后再添加子类的,这样层层继承下去仅需根据offset的值就能直接使用父类或自己的成员变量了。

    相关文章

      网友评论

        本文标题:iOS中成员变量的内存偏移量(ivar_offset)研究

        本文链接:https://www.haomeiwen.com/subject/otkhmxtx.html