在学习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的值就能直接使用父类或自己的成员变量了。
网友评论